fix: preview block
This commit is contained in:
parent
afdf281631
commit
8c125e4d21
@ -1,130 +1,132 @@
|
|||||||
import { PointsIcon } from "@icons/questionsPage/PointsIcon";
|
|
||||||
import { Box, IconButton } from "@mui/material";
|
import { Box, IconButton } from "@mui/material";
|
||||||
import { toggleQuizPreview, useQuizPreviewStore } from "@root/quizPreview";
|
import { toggleQuizPreview, useQuizPreviewStore } from "@root/quizPreview";
|
||||||
import { useLayoutEffect, useRef } from "react";
|
import { useLayoutEffect, useRef } from "react";
|
||||||
import { Rnd } from "react-rnd";
|
import { Rnd } from "react-rnd";
|
||||||
import QuizPreviewLayout from "./QuizPreviewLayout";
|
import QuizPreviewLayout from "./QuizPreviewLayout";
|
||||||
import ResizeIcon from "./ResizeIcon";
|
import ResizeIcon from "./ResizeIcon";
|
||||||
import VisibilityIcon from '@mui/icons-material/Visibility';
|
import VisibilityIcon from "@mui/icons-material/Visibility";
|
||||||
|
|
||||||
|
const DRAG_PARENT_MARGIN = 0;
|
||||||
const DRAG_PARENT_MARGIN = 25;
|
const NAVBAR_HEIGHT = 0;
|
||||||
const NAVBAR_HEIGHT = 81;
|
const DRAG_PARENT_BOTTOM_MARGIN = 0;
|
||||||
const DRAG_PARENT_BOTTOM_MARGIN = 65;
|
|
||||||
|
|
||||||
interface RndPositionAndSize {
|
interface RndPositionAndSize {
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
width: string;
|
width: string;
|
||||||
height: string;
|
height: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function QuizPreview() {
|
export default function QuizPreview() {
|
||||||
const isPreviewShown = useQuizPreviewStore(state => state.isPreviewShown);
|
const isPreviewShown = useQuizPreviewStore((state) => state.isPreviewShown);
|
||||||
const rndParentRef = useRef<HTMLDivElement>(null);
|
const rndParentRef = useRef<HTMLDivElement>(null);
|
||||||
const rndRef = useRef<Rnd | null>(null);
|
const rndRef = useRef<Rnd | null>(null);
|
||||||
const rndPositionAndSizeRef = useRef<RndPositionAndSize>({ x: 0, y: 0, width: "340", height: "480" });
|
const rndPositionAndSizeRef = useRef<RndPositionAndSize>({
|
||||||
const isFirstShowRef = useRef<boolean>(true);
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: "340",
|
||||||
|
height: "480",
|
||||||
|
});
|
||||||
|
const isFirstShowRef = useRef<boolean>(true);
|
||||||
|
|
||||||
useLayoutEffect(function stickPreviewToBottomRight() {
|
useLayoutEffect(
|
||||||
const rnd = rndRef.current;
|
function stickPreviewToBottomRight() {
|
||||||
const rndSelfElement = rnd?.getSelfElement();
|
const rnd = rndRef.current;
|
||||||
if (!rnd || !rndSelfElement || !rndParentRef.current || !isFirstShowRef.current) return;
|
const rndSelfElement = rnd?.getSelfElement();
|
||||||
|
if (
|
||||||
|
!rnd ||
|
||||||
|
!rndSelfElement ||
|
||||||
|
!rndParentRef.current ||
|
||||||
|
!isFirstShowRef.current
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
|
||||||
const rndParentRect = rndParentRef.current.getBoundingClientRect();
|
const rndParentRect = rndParentRef.current.getBoundingClientRect();
|
||||||
const rndRect = rndSelfElement.getBoundingClientRect();
|
const rndRect = rndSelfElement.getBoundingClientRect();
|
||||||
|
|
||||||
const x = rndParentRect.width - rndRect.width;
|
const x = rndParentRect.width - rndRect.width;
|
||||||
const y = rndParentRect.height - rndRect.height;
|
const y = rndParentRect.height - rndRect.height;
|
||||||
|
|
||||||
rnd.updatePosition({ x, y });
|
rnd.updatePosition({ x, y });
|
||||||
rndPositionAndSizeRef.current.x = x;
|
rndPositionAndSizeRef.current.x = x;
|
||||||
rndPositionAndSizeRef.current.y = y;
|
rndPositionAndSizeRef.current.y = y;
|
||||||
|
|
||||||
isFirstShowRef.current = false;
|
isFirstShowRef.current = false;
|
||||||
}, [isPreviewShown]);
|
},
|
||||||
|
[isPreviewShown]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
ref={rndParentRef}
|
ref={rndParentRef}
|
||||||
sx={{
|
sx={{
|
||||||
position: "fixed",
|
position: "fixed",
|
||||||
top: NAVBAR_HEIGHT + DRAG_PARENT_MARGIN,
|
top: NAVBAR_HEIGHT + DRAG_PARENT_MARGIN,
|
||||||
left: DRAG_PARENT_MARGIN,
|
left: DRAG_PARENT_MARGIN,
|
||||||
bottom: DRAG_PARENT_BOTTOM_MARGIN,
|
bottom: DRAG_PARENT_BOTTOM_MARGIN,
|
||||||
right: DRAG_PARENT_MARGIN,
|
right: DRAG_PARENT_MARGIN,
|
||||||
// backgroundColor: "rgba(0, 100, 0, 0.2)",
|
// backgroundColor: "rgba(0, 100, 0, 0.2)",
|
||||||
pointerEvents: "none",
|
pointerEvents: "none",
|
||||||
zIndex: 100,
|
zIndex: 100,
|
||||||
}}
|
}}
|
||||||
|
>
|
||||||
|
{isPreviewShown && (
|
||||||
|
<Rnd
|
||||||
|
minHeight={20}
|
||||||
|
minWidth={20}
|
||||||
|
bounds="parent"
|
||||||
|
ref={rndRef}
|
||||||
|
dragHandleClassName="quiz-preview-draghandle"
|
||||||
|
default={{
|
||||||
|
x: rndPositionAndSizeRef.current.x,
|
||||||
|
y: rndPositionAndSizeRef.current.y,
|
||||||
|
width: rndPositionAndSizeRef.current.width,
|
||||||
|
height: rndPositionAndSizeRef.current.height,
|
||||||
|
}}
|
||||||
|
onResizeStop={(e, direction, ref, delta, position) => {
|
||||||
|
rndPositionAndSizeRef.current.x = position.x;
|
||||||
|
rndPositionAndSizeRef.current.y = position.y;
|
||||||
|
rndPositionAndSizeRef.current.width = ref.style.width;
|
||||||
|
rndPositionAndSizeRef.current.height = ref.style.height;
|
||||||
|
}}
|
||||||
|
onDragStop={(e, d) => {
|
||||||
|
rndPositionAndSizeRef.current.x = d.x;
|
||||||
|
rndPositionAndSizeRef.current.y = d.y;
|
||||||
|
}}
|
||||||
|
onDragStart={(e, d) => {
|
||||||
|
e.preventDefault();
|
||||||
|
}}
|
||||||
|
enableResizing={{
|
||||||
|
topLeft: isPreviewShown,
|
||||||
|
}}
|
||||||
|
resizeHandleComponent={{
|
||||||
|
topLeft: <ResizeIcon />,
|
||||||
|
}}
|
||||||
|
resizeHandleStyles={{
|
||||||
|
topLeft: {
|
||||||
|
top: "-1px",
|
||||||
|
left: "-1px",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
overflow: "hidden",
|
||||||
|
pointerEvents: "auto",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{isPreviewShown &&
|
<QuizPreviewLayout />
|
||||||
<Rnd
|
</Rnd>
|
||||||
minHeight={300}
|
)}
|
||||||
minWidth={340}
|
<IconButton
|
||||||
bounds="parent"
|
onClick={toggleQuizPreview}
|
||||||
ref={rndRef}
|
sx={{
|
||||||
dragHandleClassName="quiz-preview-draghandle"
|
position: "absolute",
|
||||||
default={{
|
right: 0,
|
||||||
x: rndPositionAndSizeRef.current.x,
|
bottom: -54,
|
||||||
y: rndPositionAndSizeRef.current.y,
|
pointerEvents: "auto",
|
||||||
width: rndPositionAndSizeRef.current.width,
|
}}
|
||||||
height: rndPositionAndSizeRef.current.height
|
>
|
||||||
}}
|
<VisibilityIcon sx={{ height: "30px", width: "30px" }} />
|
||||||
onResizeStop={(e, direction, ref, delta, position) => {
|
</IconButton>
|
||||||
rndPositionAndSizeRef.current.x = position.x;
|
</Box>
|
||||||
rndPositionAndSizeRef.current.y = position.y;
|
);
|
||||||
rndPositionAndSizeRef.current.width = ref.style.width;
|
|
||||||
rndPositionAndSizeRef.current.height = ref.style.height;
|
|
||||||
}}
|
|
||||||
onDragStop={(e, d) => {
|
|
||||||
rndPositionAndSizeRef.current.x = d.x;
|
|
||||||
rndPositionAndSizeRef.current.y = d.y;
|
|
||||||
}}
|
|
||||||
onDragStart={(e, d) => {
|
|
||||||
e.preventDefault();
|
|
||||||
}}
|
|
||||||
enableResizing={{
|
|
||||||
topLeft: isPreviewShown,
|
|
||||||
}}
|
|
||||||
resizeHandleComponent={{
|
|
||||||
topLeft: <ResizeIcon />
|
|
||||||
}}
|
|
||||||
resizeHandleStyles={{
|
|
||||||
topLeft: {
|
|
||||||
top: "-1px",
|
|
||||||
left: "-1px",
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
style={{
|
|
||||||
pointerEvents: "auto",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<QuizPreviewLayout />
|
|
||||||
<IconButton
|
|
||||||
className="quiz-preview-draghandle"
|
|
||||||
sx={{
|
|
||||||
position: "absolute",
|
|
||||||
bottom: -54,
|
|
||||||
right: 46,
|
|
||||||
cursor: "move",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<PointsIcon style={{ color: "#4D4D4D", fontSize: "30px" }} />
|
|
||||||
</IconButton>
|
|
||||||
</Rnd>
|
|
||||||
}
|
|
||||||
<IconButton
|
|
||||||
onClick={toggleQuizPreview}
|
|
||||||
sx={{
|
|
||||||
position: "absolute",
|
|
||||||
right: 0,
|
|
||||||
bottom: -54,
|
|
||||||
pointerEvents: "auto",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<VisibilityIcon sx={{ height: "30px", width: "30px" }} />
|
|
||||||
</IconButton>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,10 @@
|
|||||||
import { Box, Button, LinearProgress, Paper, Typography } from "@mui/material";
|
import { Box, Button, LinearProgress, Paper, Typography } from "@mui/material";
|
||||||
import { questionStore } from "@root/questions";
|
import { questionStore } from "@root/questions";
|
||||||
import { decrementCurrentQuestionIndex, incrementCurrentQuestionIndex, useQuizPreviewStore } from "@root/quizPreview";
|
import {
|
||||||
|
decrementCurrentQuestionIndex,
|
||||||
|
incrementCurrentQuestionIndex,
|
||||||
|
useQuizPreviewStore,
|
||||||
|
} from "@root/quizPreview";
|
||||||
import { DefiniteQuestionType } from "model/questionTypes/shared";
|
import { DefiniteQuestionType } from "model/questionTypes/shared";
|
||||||
import { FC, useEffect } from "react";
|
import { FC, useEffect } from "react";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
@ -17,117 +21,143 @@ import Text from "./QuizPreviewQuestionTypes/Text";
|
|||||||
import Variant from "./QuizPreviewQuestionTypes/Variant";
|
import Variant from "./QuizPreviewQuestionTypes/Variant";
|
||||||
import Varimg from "./QuizPreviewQuestionTypes/Varimg";
|
import Varimg from "./QuizPreviewQuestionTypes/Varimg";
|
||||||
|
|
||||||
|
|
||||||
const QuestionPreviewComponentByType: Record<DefiniteQuestionType, FC<any>> = {
|
const QuestionPreviewComponentByType: Record<DefiniteQuestionType, FC<any>> = {
|
||||||
variant: Variant,
|
variant: Variant,
|
||||||
images: Images,
|
images: Images,
|
||||||
varimg: Varimg,
|
varimg: Varimg,
|
||||||
emoji: Emoji,
|
emoji: Emoji,
|
||||||
text: Text,
|
text: Text,
|
||||||
select: Select,
|
select: Select,
|
||||||
date: Date,
|
date: Date,
|
||||||
number: Number,
|
number: Number,
|
||||||
file: File,
|
file: File,
|
||||||
page: Page,
|
page: Page,
|
||||||
rating: Rating,
|
rating: Rating,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function QuizPreviewLayout() {
|
export default function QuizPreviewLayout() {
|
||||||
const quizId = useParams().quizId ?? 0;
|
const quizId = useParams().quizId ?? 0;
|
||||||
const listQuestions = questionStore(state => state.listQuestions);
|
const listQuestions = questionStore((state) => state.listQuestions);
|
||||||
const currentQuizStep = useQuizPreviewStore(state => state.currentQuestionIndex);
|
const currentQuizStep = useQuizPreviewStore(
|
||||||
|
(state) => state.currentQuestionIndex
|
||||||
|
);
|
||||||
|
|
||||||
const quizQuestions = listQuestions[quizId] ?? [];
|
const quizQuestions = listQuestions[quizId] ?? [];
|
||||||
const nonDeletedQuizQuestions = quizQuestions.filter(question => !question.deleted);
|
const nonDeletedQuizQuestions = quizQuestions.filter(
|
||||||
const maxCurrentQuizStep = nonDeletedQuizQuestions.length > 0 ? nonDeletedQuizQuestions.length - 1 : 0;
|
(question) => !question.deleted
|
||||||
const currentProgress = Math.floor((currentQuizStep / maxCurrentQuizStep) * 100);
|
);
|
||||||
|
const maxCurrentQuizStep =
|
||||||
|
nonDeletedQuizQuestions.length > 0 ? nonDeletedQuizQuestions.length - 1 : 0;
|
||||||
|
const currentProgress = Math.floor(
|
||||||
|
(currentQuizStep / maxCurrentQuizStep) * 100
|
||||||
|
);
|
||||||
|
|
||||||
const currentQuestion = nonDeletedQuizQuestions[currentQuizStep];
|
const currentQuestion = nonDeletedQuizQuestions[currentQuizStep];
|
||||||
const QuestionComponent = currentQuestion
|
const QuestionComponent = currentQuestion
|
||||||
? QuestionPreviewComponentByType[currentQuestion.type as DefiniteQuestionType]
|
? QuestionPreviewComponentByType[
|
||||||
: null;
|
currentQuestion.type as DefiniteQuestionType
|
||||||
|
]
|
||||||
|
: null;
|
||||||
|
|
||||||
const questionElement = QuestionComponent
|
const questionElement = QuestionComponent ? (
|
||||||
? <QuestionComponent key={currentQuestion.id} question={currentQuestion} />
|
<QuestionComponent key={currentQuestion.id} question={currentQuestion} />
|
||||||
: null;
|
) : null;
|
||||||
|
|
||||||
useEffect(function resetCurrentQuizStep() {
|
useEffect(
|
||||||
if (currentQuizStep > maxCurrentQuizStep) {
|
function resetCurrentQuizStep() {
|
||||||
decrementCurrentQuestionIndex();
|
if (currentQuizStep > maxCurrentQuizStep) {
|
||||||
}
|
decrementCurrentQuestionIndex();
|
||||||
}, [currentQuizStep, maxCurrentQuizStep]);
|
}
|
||||||
|
},
|
||||||
|
[currentQuizStep, maxCurrentQuizStep]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper sx={{
|
<Paper
|
||||||
height: "100%",
|
className="quiz-preview-draghandle"
|
||||||
|
sx={{
|
||||||
|
height: "100%",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
flexGrow: 1,
|
||||||
|
borderRadius: "12px",
|
||||||
|
pointerEvents: "auto",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
p: "16px",
|
||||||
|
whiteSpace: "break-spaces",
|
||||||
|
overflowY: "auto",
|
||||||
|
flexGrow: 1,
|
||||||
|
"&::-webkit-scrollbar": { width: 0 },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{questionElement}
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
mt: "auto",
|
||||||
|
p: "16px",
|
||||||
|
display: "flex",
|
||||||
|
borderTop: "1px solid #E3E3E3",
|
||||||
|
alignItems: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
flexGrow: 1,
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
flexGrow: 1,
|
gap: 1,
|
||||||
borderRadius: "12px",
|
}}
|
||||||
pointerEvents: "auto",
|
>
|
||||||
}}>
|
<Typography>
|
||||||
<Box sx={{
|
{nonDeletedQuizQuestions.length > 0
|
||||||
p: "16px",
|
? `Вопрос ${currentQuizStep + 1} из ${
|
||||||
whiteSpace: "break-spaces",
|
nonDeletedQuizQuestions.length
|
||||||
overflowY: "auto",
|
}`
|
||||||
flexGrow: 1,
|
: "Нет вопросов"}
|
||||||
}}>
|
</Typography>
|
||||||
{questionElement}
|
{nonDeletedQuizQuestions.length > 0 && (
|
||||||
</Box>
|
<LinearProgress
|
||||||
<Box sx={{
|
variant="determinate"
|
||||||
mt: "auto",
|
value={currentProgress}
|
||||||
p: "16px",
|
sx={{
|
||||||
display: "flex",
|
"&.MuiLinearProgress-colorPrimary": {
|
||||||
borderTop: "1px solid #E3E3E3",
|
backgroundColor: "fadePurple.main",
|
||||||
alignItems: "center",
|
},
|
||||||
}}>
|
"& .MuiLinearProgress-barColorPrimary": {
|
||||||
<Box sx={{
|
backgroundColor: "brightPurple.main",
|
||||||
flexGrow: 1,
|
},
|
||||||
display: "flex",
|
}}
|
||||||
flexDirection: "column",
|
/>
|
||||||
gap: 1,
|
)}
|
||||||
}}>
|
</Box>
|
||||||
<Typography>
|
<Box
|
||||||
{nonDeletedQuizQuestions.length > 0
|
sx={{
|
||||||
? `Вопрос ${currentQuizStep + 1} из ${nonDeletedQuizQuestions.length}`
|
ml: 2,
|
||||||
: "Нет вопросов"
|
display: "flex",
|
||||||
}
|
gap: 1,
|
||||||
</Typography>
|
}}
|
||||||
{nonDeletedQuizQuestions.length > 0 &&
|
>
|
||||||
<LinearProgress
|
<Button
|
||||||
variant="determinate"
|
variant="outlined"
|
||||||
value={currentProgress}
|
onClick={decrementCurrentQuestionIndex}
|
||||||
sx={{
|
disabled={currentQuizStep === 0}
|
||||||
"&.MuiLinearProgress-colorPrimary": {
|
sx={{ px: 1, minWidth: 0 }}
|
||||||
backgroundColor: "fadePurple.main",
|
>
|
||||||
},
|
<ArrowLeft />
|
||||||
"& .MuiLinearProgress-barColorPrimary": {
|
</Button>
|
||||||
backgroundColor: "brightPurple.main",
|
<Button
|
||||||
},
|
variant="contained"
|
||||||
}}
|
onClick={() => incrementCurrentQuestionIndex(maxCurrentQuizStep)}
|
||||||
/>
|
disabled={currentQuizStep >= maxCurrentQuizStep}
|
||||||
}
|
>
|
||||||
</Box>
|
Далее
|
||||||
<Box sx={{
|
</Button>
|
||||||
ml: 2,
|
</Box>
|
||||||
display: "flex",
|
</Box>
|
||||||
gap: 1,
|
</Paper>
|
||||||
}}>
|
);
|
||||||
<Button
|
|
||||||
variant="outlined"
|
|
||||||
onClick={decrementCurrentQuestionIndex}
|
|
||||||
disabled={currentQuizStep === 0}
|
|
||||||
sx={{ px: 1, minWidth: 0 }}
|
|
||||||
>
|
|
||||||
<ArrowLeft />
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
onClick={() => incrementCurrentQuestionIndex(maxCurrentQuizStep)}
|
|
||||||
disabled={currentQuizStep >= maxCurrentQuizStep}
|
|
||||||
>Далее</Button>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
</Paper>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user