add question select for preview
This commit is contained in:
parent
75d313e0d7
commit
a5051e8ebc
@ -6,93 +6,53 @@ import { useQuizData } from "@contexts/QuizDataContext";
|
||||
import Stepper from "@ui_kit/Stepper";
|
||||
|
||||
type FooterProps = {
|
||||
stepNumber: number | null;
|
||||
nextButton: ReactNode;
|
||||
prevButton: ReactNode;
|
||||
stepNumber: number | null;
|
||||
nextButton: ReactNode;
|
||||
prevButton: ReactNode;
|
||||
};
|
||||
|
||||
export const Footer = ({ stepNumber, nextButton, prevButton }: FooterProps) => {
|
||||
const theme = useTheme();
|
||||
const { questions, settings } = useQuizData();
|
||||
const questionsAmount = questions.filter(
|
||||
({ type }) => type !== "result"
|
||||
).length;
|
||||
if (stepNumber === null) stepNumber = -1
|
||||
console.log("stepNumber ", stepNumber)
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
position: "relative",
|
||||
padding: "15px 0",
|
||||
borderTop: `1px solid #9A9AAF80`,
|
||||
height: "75px",
|
||||
display: "flex",
|
||||
background: settings.cfg.design
|
||||
? "rgba(154,154,175, 0.2)"
|
||||
: "transparent",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
maxWidth: "1410px",
|
||||
padding: "10px",
|
||||
margin: "0 auto",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "10px",
|
||||
}}
|
||||
>
|
||||
{/*{mode[settings.cfg.theme] ? (*/}
|
||||
{/* <NameplateLogoFQ style={{ fontSize: "34px", width:"200px", height:"auto" }} />*/}
|
||||
{/*):(*/}
|
||||
{/* <NameplateLogoFQDark style={{ fontSize: "34px", width:"200px", height:"auto" }} />*/}
|
||||
{/*)}*/}
|
||||
{
|
||||
questions.every(({ content }) => content.rule.parentId !== "root") !== null // null when branching enabled
|
||||
&&
|
||||
stepNumber !== null && (
|
||||
<Box sx={{ flexGrow: 1 }}>
|
||||
<Typography sx={{ color: theme.palette.text.primary }}>
|
||||
Вопрос {stepNumber} из {questionsAmount}
|
||||
</Typography>
|
||||
<Stepper activeStep={stepNumber} steps={questionsAmount} />
|
||||
</Box>
|
||||
)}
|
||||
const theme = useTheme();
|
||||
const { questions, settings } = useQuizData();
|
||||
const questionsAmount = questions.filter(
|
||||
({ type }) => type !== "result"
|
||||
).length;
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "10px",
|
||||
marginRight: "auto",
|
||||
// color: theme.palette.grey1.main,
|
||||
}}
|
||||
>
|
||||
{/* <Typography>Шаг</Typography>
|
||||
<Typography
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
fontWeight: "bold",
|
||||
borderRadius: "50%",
|
||||
width: "30px",
|
||||
height: "30px",
|
||||
color: "#FFF",
|
||||
background: theme.palette.brightPurple.main,
|
||||
position: "relative",
|
||||
padding: "15px 0",
|
||||
borderTop: `1px solid #9A9AAF80`,
|
||||
height: "75px",
|
||||
display: "flex",
|
||||
background: settings.cfg.design
|
||||
? "rgba(154,154,175, 0.2)"
|
||||
: "transparent",
|
||||
}}
|
||||
>
|
||||
{stepNumber} */}
|
||||
{/* </Typography> */}
|
||||
{/* <Typography>Из</Typography>
|
||||
<Typography sx={{ fontWeight: "bold" }}>
|
||||
{questions.length}
|
||||
</Typography> */}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
maxWidth: "1410px",
|
||||
padding: "10px",
|
||||
margin: "0 auto",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "10px",
|
||||
}}
|
||||
>
|
||||
{stepNumber !== null && (
|
||||
<Box sx={{ flexGrow: 1 }}>
|
||||
<Typography sx={{ color: theme.palette.text.primary }}>
|
||||
Вопрос {stepNumber} из {questionsAmount}
|
||||
</Typography>
|
||||
<Stepper activeStep={stepNumber} steps={questionsAmount} />
|
||||
</Box>
|
||||
)}
|
||||
{prevButton}
|
||||
{nextButton}
|
||||
</Box>
|
||||
</Box>
|
||||
{prevButton}
|
||||
{nextButton}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
);
|
||||
};
|
||||
|
@ -21,14 +21,15 @@ import { NameplateLogoFQDark } from "@icons/NameplateLogoFQDark";
|
||||
import { notReachable } from "@utils/notReachable";
|
||||
import { quizThemes } from "@utils/themes/Publication/themePublication";
|
||||
|
||||
import type { ReactNode } from "react";
|
||||
import { DESIGN_LIST } from "@/utils/designList";
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
type Props = {
|
||||
currentQuestion: RealTypedQuizQuestion;
|
||||
currentQuestionStepNumber: number | null;
|
||||
nextButton: ReactNode;
|
||||
prevButton: ReactNode;
|
||||
questionSelect: ReactNode;
|
||||
};
|
||||
|
||||
export const Question = ({
|
||||
@ -36,6 +37,7 @@ export const Question = ({
|
||||
currentQuestionStepNumber,
|
||||
nextButton,
|
||||
prevButton,
|
||||
questionSelect,
|
||||
}: Props) => {
|
||||
const theme = useTheme();
|
||||
const { settings, show_badge } = useQuizData();
|
||||
@ -118,6 +120,7 @@ export const Question = ({
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
{questionSelect}
|
||||
<Footer
|
||||
stepNumber={currentQuestionStepNumber}
|
||||
prevButton={prevButton}
|
||||
|
112
lib/components/ViewPublicationPage/QuestionSelect.tsx
Normal file
112
lib/components/ViewPublicationPage/QuestionSelect.tsx
Normal file
@ -0,0 +1,112 @@
|
||||
import { useQuizData } from "@/contexts/QuizDataContext";
|
||||
import { AnyTypedQuizQuestion } from "@/model/questionTypes/shared";
|
||||
import { Box, FormControl, MenuItem, Select as MuiSelect, useTheme } from "@mui/material";
|
||||
|
||||
|
||||
interface Props {
|
||||
selectedQuestion: AnyTypedQuizQuestion;
|
||||
setQuestion: (questionIdF: string) => void;
|
||||
}
|
||||
|
||||
export default function QuestionSelect({ selectedQuestion, setQuestion }: Props) {
|
||||
const theme = useTheme();
|
||||
const { questions, preview } = useQuizData();
|
||||
|
||||
if (!preview) return null;
|
||||
|
||||
return (
|
||||
<Box sx={{
|
||||
p: "20px",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
}}>
|
||||
<FormControl
|
||||
fullWidth
|
||||
size="small"
|
||||
sx={{
|
||||
maxWidth: "500px",
|
||||
minWidth: "200px",
|
||||
height: "48px",
|
||||
|
||||
}}
|
||||
className="cancel"
|
||||
>
|
||||
<MuiSelect
|
||||
id="category-select"
|
||||
variant="outlined"
|
||||
value={selectedQuestion.id}
|
||||
placeholder="Заголовок вопроса"
|
||||
onChange={({ target }) => {
|
||||
setQuestion(target.value);
|
||||
}}
|
||||
sx={{
|
||||
height: "48px",
|
||||
borderRadius: "8px",
|
||||
"& .MuiOutlinedInput-notchedOutline": {
|
||||
border: `1px solid ${theme.palette.primary.main} !important`,
|
||||
},
|
||||
"& .MuiSelect-icon": {
|
||||
color: theme.palette.primary.main,
|
||||
},
|
||||
}}
|
||||
MenuProps={{
|
||||
PaperProps: {
|
||||
sx: {
|
||||
mt: "8px",
|
||||
p: "4px",
|
||||
borderRadius: "8px",
|
||||
border: "1px solid #EEE4FC",
|
||||
boxShadow: "0px 8px 24px rgba(210, 208, 225, 0.4)",
|
||||
backgroundColor: theme.palette.background.default,
|
||||
},
|
||||
},
|
||||
MenuListProps: {
|
||||
sx: {
|
||||
py: 0,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "8px",
|
||||
"& .Mui-selected": {
|
||||
backgroundColor: theme.palette.background.default,
|
||||
color: theme.palette.primary.main,
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
inputProps={{
|
||||
sx: {
|
||||
color: theme.palette.primary.main,
|
||||
display: "block",
|
||||
px: "9px",
|
||||
gap: "20px",
|
||||
width: "87%",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
},
|
||||
}}
|
||||
>
|
||||
{questions.filter((q) => q.type !== "result").map(
|
||||
(question, index) => (
|
||||
<MenuItem
|
||||
key={question.id}
|
||||
value={question.id}
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "20px",
|
||||
p: "4px",
|
||||
borderRadius: "5px",
|
||||
color: "#9A9AAF",
|
||||
wordBreak: "break-word",
|
||||
whiteSpace: "normal",
|
||||
}}
|
||||
>
|
||||
{`${index + 1}. ${question.title}`}
|
||||
</MenuItem>
|
||||
),
|
||||
)}
|
||||
</MuiSelect>
|
||||
</FormControl>
|
||||
</Box>
|
||||
);
|
||||
}
|
@ -5,6 +5,7 @@ import { useQuizViewStore } from "@stores/quizView";
|
||||
import { useQuestionFlowControl } from "@utils/hooks/useQuestionFlowControl";
|
||||
import { notReachable } from "@utils/notReachable";
|
||||
import { quizThemes } from "@utils/themes/Publication/themePublication";
|
||||
import "https://markknol.github.io/console-log-viewer/console-log-viewer.js";
|
||||
import { enqueueSnackbar } from "notistack";
|
||||
import { ReactElement, useEffect } from "react";
|
||||
import { ContactForm } from "./ContactForm";
|
||||
@ -13,7 +14,7 @@ import { ResultForm } from "./ResultForm";
|
||||
import { StartPageViewPublication } from "./StartPageViewPublication";
|
||||
import NextButton from "./tools/NextButton";
|
||||
import PrevButton from "./tools/PrevButton";
|
||||
import "https://markknol.github.io/console-log-viewer/console-log-viewer.js"
|
||||
import QuestionSelect from "./QuestionSelect";
|
||||
|
||||
export default function ViewPublicationPage() {
|
||||
const { settings, recentlyCompleted, quizId, preview, changeFaviconAndTitle } = useQuizData();
|
||||
@ -27,6 +28,7 @@ export default function ViewPublicationPage() {
|
||||
moveToPrevQuestion,
|
||||
moveToNextQuestion,
|
||||
showResultAfterContactForm,
|
||||
setQuestion,
|
||||
} = useQuestionFlowControl();
|
||||
|
||||
const isAnswer = answers.some(ans => ans.questionId === currentQuestion.id);
|
||||
@ -81,7 +83,14 @@ export default function ViewPublicationPage() {
|
||||
}
|
||||
moveToNextQuestion();
|
||||
}}
|
||||
/>}
|
||||
/>
|
||||
}
|
||||
questionSelect={
|
||||
<QuestionSelect
|
||||
selectedQuestion={currentQuestion}
|
||||
setQuestion={setQuestion}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
|
@ -1,22 +1,23 @@
|
||||
import {Button, useTheme} from "@mui/material";
|
||||
import {useRootContainerSize} from "../../../contexts/RootContainerWidthContext";
|
||||
import { Button, useTheme } from "@mui/material";
|
||||
import { useRootContainerSize } from "../../../contexts/RootContainerWidthContext";
|
||||
import { quizThemes } from "@utils/themes/Publication/themePublication";
|
||||
import { useQuizData } from "@contexts/QuizDataContext";
|
||||
|
||||
interface Props{
|
||||
interface Props {
|
||||
isPreviousButtonEnabled: boolean,
|
||||
moveToPrevQuestion: () => void,
|
||||
}
|
||||
|
||||
export default function PrevButton ({isPreviousButtonEnabled, moveToPrevQuestion}: Props) {
|
||||
export default function PrevButton({ isPreviousButtonEnabled, moveToPrevQuestion }: Props) {
|
||||
const theme = useTheme();
|
||||
const { settings } = useQuizData();
|
||||
const isMobileMini = useRootContainerSize() < 382;
|
||||
return(
|
||||
return (
|
||||
<Button
|
||||
disabled={!isPreviousButtonEnabled}
|
||||
variant="contained"
|
||||
sx={{
|
||||
ml: "auto",
|
||||
fontSize: "16px",
|
||||
padding: "10px 15px",
|
||||
color: quizThemes[settings.cfg.theme].isLight ? theme.palette.primary.main : "#FFFFFF",
|
||||
@ -34,5 +35,5 @@ export default function PrevButton ({isPreviousButtonEnabled, moveToPrevQuestion
|
||||
>
|
||||
{isMobileMini ? "←" : "← Назад"}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -35,10 +35,10 @@ interface QuizViewActions {
|
||||
export const QuizViewContext = createContext<ReturnType<typeof createQuizViewStore> | null>(null);
|
||||
|
||||
export function useQuizViewStore<U>(selector: (state: QuizViewStore & QuizViewActions) => U): U {
|
||||
const context = useContext(QuizViewContext);
|
||||
if (!context) throw new Error("QuizViewStore context is null");
|
||||
const store = useContext(QuizViewContext);
|
||||
if (!store) throw new Error("QuizViewStore context is null");
|
||||
|
||||
return useStore(context, selector);
|
||||
return useStore(store, selector);
|
||||
}
|
||||
|
||||
export const createQuizViewStore = () => createStore<QuizViewStore & QuizViewActions>()(
|
||||
|
@ -149,7 +149,7 @@ export function useQuestionFlowControl() {
|
||||
settings.cfg.resultInfo.showResultForm === "after"
|
||||
|| isResultQuestionEmpty(nextQuestion)
|
||||
) setCurrentQuizStep("contactform");
|
||||
}, [nextQuestion, settings.cfg.resultInfo.showResultForm]);
|
||||
}, [nextQuestion, setCurrentQuizStep, settings.cfg.resultInfo.showResultForm]);
|
||||
|
||||
const showResultAfterContactForm = useCallback(() => {
|
||||
if (currentQuestion.type !== "result") throw new Error("Current question is not result");
|
||||
@ -159,7 +159,7 @@ export function useQuestionFlowControl() {
|
||||
}
|
||||
|
||||
setCurrentQuizStep("question");
|
||||
}, [currentQuestion]);
|
||||
}, [currentQuestion, setCurrentQuizStep]);
|
||||
|
||||
const moveToPrevQuestion = useCallback(() => {
|
||||
if (!prevQuestion) throw new Error("Previous question not found");
|
||||
@ -175,6 +175,13 @@ export function useQuestionFlowControl() {
|
||||
setCurrentQuestion(nextQuestion);
|
||||
}, [nextQuestion, showResult]);
|
||||
|
||||
const setQuestion = useCallback((questionId: string) => {
|
||||
const question = questions.find(q => q.id === questionId);
|
||||
if (!question) return;
|
||||
|
||||
setCurrentQuestion(question);
|
||||
}, [questions]);
|
||||
|
||||
const isPreviousButtonEnabled = Boolean(prevQuestion);
|
||||
|
||||
const isNextButtonEnabled = useMemo(() => {
|
||||
@ -202,5 +209,6 @@ export function useQuestionFlowControl() {
|
||||
moveToPrevQuestion,
|
||||
moveToNextQuestion,
|
||||
showResultAfterContactForm,
|
||||
setQuestion,
|
||||
};
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@frontend/squzanswerer",
|
||||
"version": "1.0.25",
|
||||
"version": "1.0.26",
|
||||
"type": "module",
|
||||
"main": "./dist-package/index.js",
|
||||
"module": "./dist-package/index.js",
|
||||
|
Loading…
Reference in New Issue
Block a user