мобильная версия публикации вопросов

This commit is contained in:
Tamara 2023-12-27 21:52:05 +03:00
parent ee87a5d7a8
commit 520a36423f
8 changed files with 245 additions and 129 deletions

@ -1,5 +1,5 @@
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { Box, Button, Typography, useTheme } from "@mui/material"; import {Box, Button, Typography, useMediaQuery, useTheme} from "@mui/material";
import { useQuizViewStore } from "@root/quizView"; import { useQuizViewStore } from "@root/quizView";
import { useCurrentQuiz } from "@root/quizes/hooks"; import { useCurrentQuiz } from "@root/quizes/hooks";
@ -29,6 +29,7 @@ export const Footer = ({ setCurrentQuestion, question, setShowContactForm, setSh
const { answers } = useQuizViewStore(); const { answers } = useQuizViewStore();
const questions = useQuestionsStore().questions as AnyTypedQuizQuestion[]; const questions = useQuestionsStore().questions as AnyTypedQuizQuestion[];
const theme = useTheme(); const theme = useTheme();
const isMobileMini = useMediaQuery(theme.breakpoints.down(382));
const linear = !questions.find(({ content }) => content.rule.parentId === "root"); const linear = !questions.find(({ content }) => content.rule.parentId === "root");
useEffect(() => { useEffect(() => {
@ -236,13 +237,11 @@ export const Footer = ({ setCurrentQuestion, question, setShowContactForm, setSh
gap: "10px", gap: "10px",
}} }}
> >
{mode[quiz.config.theme] ? ( {/*{mode[quiz.config.theme] ? (*/}
<NameplateLogoFQ style={{ fontSize: "34px", width:"200px", height:"auto" }} /> {/* <NameplateLogoFQ style={{ fontSize: "34px", width:"200px", height:"auto" }} />*/}
):( {/*):(*/}
<NameplateLogoFQDark style={{ fontSize: "34px", width:"200px", height:"auto" }} /> {/* <NameplateLogoFQDark style={{ fontSize: "34px", width:"200px", height:"auto" }} />*/}
) {/*)}*/}
}
{linear && {linear &&
<> <>
<Box <Box
@ -251,7 +250,7 @@ export const Footer = ({ setCurrentQuestion, question, setShowContactForm, setSh
alignItems: "center", alignItems: "center",
gap: "10px", gap: "10px",
marginRight: "auto", marginRight: "auto",
color: theme.palette.grey1.main, color: theme.palette.text.primary,
}} }}
> >
<Typography>Шаг</Typography> <Typography>Шаг</Typography>
@ -265,7 +264,7 @@ export const Footer = ({ setCurrentQuestion, question, setShowContactForm, setSh
width: "30px", width: "30px",
height: "30px", height: "30px",
color: "#FFF", color: "#FFF",
background: theme.palette.brightPurple.main, background: theme.palette.primary.main,
}} }}
> >
{stepNumber} {stepNumber}
@ -311,10 +310,16 @@ export const Footer = ({ setCurrentQuestion, question, setShowContactForm, setSh
<Button <Button
disabled={disablePreviousButton} disabled={disablePreviousButton}
variant="contained" variant="contained"
sx={{ fontSize: "16px", padding: "10px 15px", "& :disabled": {color: `{hsl((theme.palette.primary.main) 30%)}`} }} sx={{ fontSize: "16px", padding: "10px 15px",}}
onClick={followPreviousStep} onClick={followPreviousStep}
> >
Назад {isMobileMini ? (
"←"
) : (
"← Назад"
)}
</Button> </Button>
<Button <Button
disabled={disableNextButton} disabled={disableNextButton}

@ -22,6 +22,9 @@ import { ResultQuestion } from "./ResultQuestion";
import type { QuestionType } from "../../model/question/question"; import type { QuestionType } from "../../model/question/question";
import type { AnyTypedQuizQuestion } from "../../model/questionTypes/shared"; import type { AnyTypedQuizQuestion } from "../../model/questionTypes/shared";
import {NameplateLogoFQ} from "@icons/NameplateLogoFQ";
import {NameplateLogoFQDark} from "@icons/NameplateLogoFQDark";
import {modes} from "@utils/themes/Publication/themePublication";
type QuestionProps = { type QuestionProps = {
questions: AnyTypedQuizQuestion[]; questions: AnyTypedQuizQuestion[];
@ -46,7 +49,7 @@ export const Question = ({ questions }: QuestionProps) => {
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);
const mode = modes;
useEffect(() => { useEffect(() => {
const nextQuestion = getQuestionByContentId(quiz?.config.haveRoot || ""); const nextQuestion = getQuestionByContentId(quiz?.config.haveRoot || "");
@ -80,9 +83,18 @@ export const Question = ({ questions }: QuestionProps) => {
maxWidth: "1440px", maxWidth: "1440px",
padding: "40px 25px 20px", padding: "40px 25px 20px",
margin: "0 auto", margin: "0 auto",
overflow: "auto",
display: "flex",
flexDirection: "column",
justifyContent: "space-between"
}} }}
> >
<QuestionComponent currentQuestion={currentQuestion} /> <QuestionComponent currentQuestion={currentQuestion} />
{mode[quiz.config.theme] ? (
<NameplateLogoFQ style={{ fontSize: "34px", width:"200px", height:"auto" }} />
):(
<NameplateLogoFQDark style={{ fontSize: "34px", width:"200px", height:"auto" }} />
)}
</Box> </Box>
)} )}
{showResultForm && quiz?.config.resultInfo.when === "before" && ( {showResultForm && quiz?.config.resultInfo.when === "before" && (

@ -16,6 +16,7 @@ export const StartPageViewPublication = ({ setVisualStartPage }: Props) => {
const quiz = useCurrentQuiz(); const quiz = useCurrentQuiz();
const mode = modes; const mode = modes;
const { isMobileDevice } = useUADevice(); const { isMobileDevice } = useUADevice();
const isMobile = useMediaQuery(theme.breakpoints.down(650));
if (!quiz) return null; if (!quiz) return null;
@ -87,7 +88,6 @@ 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)"
: "", : "",
backgroundColor: theme.palette.background.default,
color: quiz.config.startpageType === "expanded" ? "white" : "black", color: quiz.config.startpageType === "expanded" ? "white" : "black",
}} }}
@ -152,7 +152,7 @@ export const StartPageViewPublication = ({ setVisualStartPage }: Props) => {
overflowWrap: "break-word", overflowWrap: "break-word",
width: "100%", width: "100%",
textAlign: quiz.config.startpageType === "centered" ? "center" : "-moz-initial", textAlign: quiz.config.startpageType === "centered" ? "center" : "-moz-initial",
color: theme.palette.text.primary color: quiz.config.startpageType === "expanded" ? "white" : theme.palette.text.primary
}} }}
> >
{quiz.name} {quiz.name}
@ -184,7 +184,14 @@ export const StartPageViewPublication = ({ setVisualStartPage }: Props) => {
</Box> </Box>
<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%",
flexDirection: isMobile ? "column" : "row"
}}
> >
<Box sx={{ maxWidth: "300px" }}> <Box sx={{ maxWidth: "300px" }}>
{quiz.config.info.clickable ? ( {quiz.config.info.clickable ? (
@ -218,8 +225,8 @@ export const StartPageViewPublication = ({ setVisualStartPage }: Props) => {
gap: "15px" gap: "15px"
}} }}
> >
<NameplateLogo style={{ fontSize: "34px", color: mode[quiz.config.theme] ? "#151515" : "#FFFFFF" }} /> <NameplateLogo style={{ fontSize: "34px", color: quiz.config.startpageType === "expanded" ? "#FFFFFF" : (mode[quiz.config.theme] ? "#151515" : "#FFFFFF") }} />
<Typography sx={{ fontSize: "20px", color: mode[quiz.config.theme] ? "#4D4D4D" : "#F5F7FF", whiteSpace: "nowrap", }}> <Typography sx={{ fontSize: "20px", color: quiz.config.startpageType === "expanded" ? "#F5F7FF" : (mode[quiz.config.theme] ? "#4D4D4D" : "#F5F7FF"), whiteSpace: "nowrap", }}>
Сделано на PenaQuiz Сделано на PenaQuiz
</Typography> </Typography>
</Box> </Box>
@ -248,116 +255,191 @@ function QuizPreviewLayoutByType({
alignType: QuizStartpageAlignType; alignType: QuizStartpageAlignType;
}) { }) {
const theme = useTheme(); const theme = useTheme();
const isTablet = useMediaQuery(theme.breakpoints.down(630)); const isMobile = useMediaQuery(theme.breakpoints.down(650));
function StartPageMobile() {
return(
<Box
sx={{
display: "flex",
flexDirection: "column-reverse",
flexGrow: 1,
justifyContent: "flex-end",
height: "100vh",
"&::-webkit-scrollbar": { width: 0 },
}}
>
<Box
sx={{
width: "100%",
display: "flex",
flexDirection: "column",
justifyContent: "space-between",
alignItems: "flex-start",
p: "25px",
height: "80%"
}}
>
{quizHeaderBlock}
<Box
sx={{
height: "80%",
display: "flex",
flexDirection: "column",
justifyContent: "space-between",
width: "100%"
}}
>
{quizMainBlock}
</Box>
</Box>
<Box
sx={{
width: "100%",
overflow: "hidden",
}}
>
{backgroundBlock}
</Box>
</Box>
)
}
switch (startpageType) { switch (startpageType) {
case null: case null:
case "standard": { case "standard": {
return ( return (
<Box <>
sx={{ {isMobile ? (
display: "flex", <StartPageMobile/>
flexDirection: alignType === "left" ? "row" : "row-reverse", ) : (
flexGrow: 1, <Box
height: "100vh", sx={{
"&::-webkit-scrollbar": { width: 0 }, display: "flex",
}} flexDirection: alignType === "left" ? (isMobile ? "column-reverse" : "row") : "row-reverse",
> flexGrow: 1,
<Box justifyContent: isMobile ? "flex-end" : undefined,
sx={{ height: "100vh",
width: !isTablet ? "40%" : "100%", "&::-webkit-scrollbar": { width: 0 },
display: "flex", }}
flexDirection: "column", >
justifyContent: "space-between", <Box
alignItems: !isTablet ? "flex-start" : "center", sx={{
p: "25px", width: isMobile ? "100%" : "40%",
}} display: "flex",
> flexDirection: "column",
{quizHeaderBlock} justifyContent: "space-between",
{quizMainBlock} alignItems: "flex-start",
</Box> p: "25px",
height: isMobile ? "80%" : undefined
}}
>
{quizHeaderBlock}
{quizMainBlock}
</Box>
<Box
sx={{
width: isMobile ? "100%" : "60%",
overflow: "hidden",
}}
>
{backgroundBlock}
</Box>
</Box>
)}
</>
<Box
sx={{
width: "60%",
overflow: "hidden",
}}
>
{backgroundBlock}
</Box>
</Box>
); );
} }
case "expanded": { case "expanded": {
return ( return (
<Box <>
sx={{ {isMobile ? (
position: "relative", <StartPageMobile/>
display: "flex", ) : (
justifyContent: startpageAlignTypeToJustifyContent[alignType], <Box
flexGrow: 1, sx={{
height: "100%", position: "relative",
"&::-webkit-scrollbar": { width: 0 }, display: "flex",
}} justifyContent: startpageAlignTypeToJustifyContent[alignType],
> flexGrow: 1,
<Box height: "100%",
sx={{ "&::-webkit-scrollbar": { width: 0 },
width: "40%", }}
position: "relative", >
padding: "16px", <Box
zIndex: 3, sx={{
display: "flex", width: "40%",
flexDirection: "column", position: "relative",
justifyContent: "space-between", padding: "16px",
alignItems: alignType === "center" ? "center" : "start", zIndex: 3,
}} display: "flex",
> flexDirection: "column",
{quizHeaderBlock} justifyContent: "space-between",
{quizMainBlock} alignItems: alignType === "center" ? "center" : "start",
</Box> }}
<Box >
sx={{ {quizHeaderBlock}
position: "absolute", {quizMainBlock}
zIndex: -1, </Box>
left: 0, <Box
top: 0, sx={{
height: "100%", position: "absolute",
width: "100%", zIndex: -1,
overflow: "hidden", left: 0,
}} top: 0,
> height: "100%",
{backgroundBlock} width: "100%",
</Box> overflow: "hidden",
</Box> }}
>
{backgroundBlock}
</Box>
</Box>
)
}
</>
); );
} }
case "centered": { case "centered": {
return ( return (
<Box <>
sx={{ {isMobile ? (
padding: "16px", <StartPageMobile/>
display: "flex", ) : (
flexDirection: "column", <Box
justifyContent: "center", sx={{
alignItems: "center", padding: "16px",
height: "100%", display: "flex",
"&::-webkit-scrollbar": { width: 0 }, flexDirection: "column",
overflow: "hidden", justifyContent: "center",
}} alignItems: "center",
> height: "100%",
{quizHeaderBlock} "&::-webkit-scrollbar": { width: 0 },
{backgroundBlock && ( overflow: "hidden",
<Box }}
sx={{ >
width: "60%", {quizHeaderBlock}
overflow: "hidden", {backgroundBlock && (
}} <Box
> sx={{
{backgroundBlock} width: "60%",
</Box> overflow: "hidden",
)} }}
{quizMainBlock} >
</Box> {backgroundBlock}
</Box>
)}
{quizMainBlock}
</Box>
)
}
</>
); );
} }
default: default:

@ -58,7 +58,7 @@ export const ViewPage = () => {
if (questions.length === 0 || (questions.length === 1 && questions[0].type === "result")) return <ApologyPage message="Нет созданных вопросов"/> if (questions.length === 0 || (questions.length === 1 && questions[0].type === "result")) return <ApologyPage message="Нет созданных вопросов"/>
return ( return (
<ThemeProvider theme={themesPublication?.[quiz?.config.theme]}> <ThemeProvider theme={themesPublication?.[quiz?.config.theme]}>
<Box sx={{backgroundColor: theme.palette.background.default}}> <Box sx={{backgroundColor: quiz.config.startpageType === "expanded" ? undefined : theme.palette.background.default}}>
{!visualStartPage ? ( {!visualStartPage ? (
<StartPageViewPublication setVisualStartPage={setVisualStartPage} /> <StartPageViewPublication setVisualStartPage={setVisualStartPage} />
) : ( ) : (

@ -5,7 +5,7 @@ import {
FormControlLabel, FormControlLabel,
Radio, Radio,
useTheme, useTheme,
FormControl, FormControl, useMediaQuery,
} from "@mui/material"; } from "@mui/material";
import { useQuizViewStore, updateAnswer, deleteAnswer } from "@root/quizView"; import { useQuizViewStore, updateAnswer, deleteAnswer } from "@root/quizView";
@ -22,6 +22,7 @@ type EmojiProps = {
export const Emoji = ({ currentQuestion }: EmojiProps) => { export const Emoji = ({ currentQuestion }: EmojiProps) => {
const { answers } = useQuizViewStore(); const { answers } = useQuizViewStore();
const theme = useTheme(); const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(650));
const { answer } = const { answer } =
answers.find( answers.find(
({ questionId }) => questionId === currentQuestion.content.id ({ questionId }) => questionId === currentQuestion.content.id
@ -49,7 +50,7 @@ export const Emoji = ({ currentQuestion }: EmojiProps) => {
marginTop: "20px", marginTop: "20px",
}} }}
> >
<Box sx={{ display: "flex", width: "100%", gap: "42px" }}> <Box sx={{ display: "flex", width: "100%", gap: "42px", flexWrap: "wrap" }}>
{currentQuestion.content.variants.map((variant, index) => ( {currentQuestion.content.variants.map((variant, index) => (
<FormControl <FormControl
key={variant.id} key={variant.id}

@ -1,5 +1,5 @@
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { Box, Typography, Slider, useTheme } from "@mui/material"; import {Box, Typography, Slider, useTheme, useMediaQuery} from "@mui/material";
import { useDebouncedCallback } from "use-debounce"; import { useDebouncedCallback } from "use-debounce";
import CustomTextField from "@ui_kit/CustomTextField"; import CustomTextField from "@ui_kit/CustomTextField";
@ -19,6 +19,7 @@ export const Number = ({ currentQuestion }: NumberProps) => {
const [minRange, setMinRange] = useState<string>("0"); const [minRange, setMinRange] = useState<string>("0");
const [maxRange, setMaxRange] = useState<string>("100000000000"); const [maxRange, setMaxRange] = useState<string>("100000000000");
const theme = useTheme(); const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(650));
const mode = modes; const mode = modes;
const quiz = useCurrentQuiz(); const quiz = useCurrentQuiz();
const { answers } = useQuizViewStore(); const { answers } = useQuizViewStore();
@ -72,6 +73,7 @@ export const Number = ({ currentQuestion }: NumberProps) => {
width: "100%", width: "100%",
marginTop: "20px", marginTop: "20px",
gap: "30px", gap: "30px",
paddingRight: isMobile ? "10px" : undefined
}} }}
> >
<CustomSlider <CustomSlider

@ -2,7 +2,7 @@ import {
Box, Box,
Typography, Typography,
Rating as RatingComponent, Rating as RatingComponent,
useTheme, useTheme, useMediaQuery,
} from "@mui/material"; } from "@mui/material";
import { useQuizViewStore, updateAnswer } from "@root/quizView"; import { useQuizViewStore, updateAnswer } from "@root/quizView";
@ -55,6 +55,7 @@ const buttonRatingForm = [
export const Rating = ({ currentQuestion }: RatingProps) => { export const Rating = ({ currentQuestion }: RatingProps) => {
const { answers } = useQuizViewStore(); const { answers } = useQuizViewStore();
const theme = useTheme(); const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(650));
const { answer } = const { answer } =
answers.find( answers.find(
({ questionId }) => questionId === currentQuestion.content.id ({ questionId }) => questionId === currentQuestion.content.id
@ -72,6 +73,7 @@ export const Rating = ({ currentQuestion }: RatingProps) => {
alignItems: "center", alignItems: "center",
gap: "20px", gap: "20px",
marginTop: "20px", marginTop: "20px",
width: isMobile ? "100%" : undefined
}} }}
> >
<Typography sx={{ <Typography sx={{
@ -91,7 +93,11 @@ export const Rating = ({ currentQuestion }: RatingProps) => {
onChange={(_, value) => onChange={(_, value) =>
updateAnswer(currentQuestion.content.id, String(value)) updateAnswer(currentQuestion.content.id, String(value))
} }
sx={{ height: "50px", gap: "15px" }} sx={{ height: "50px",
gap: isMobile ? undefined : "15px",
justifyContent: isMobile ? "space-between" : undefined,
width: isMobile ? "100%" : undefined
}}
max={currentQuestion.content.steps} max={currentQuestion.content.steps}
icon={form?.icon(theme.palette.primary.main)} icon={form?.icon(theme.palette.primary.main)}
emptyIcon={form?.icon("#9A9AAF")} emptyIcon={form?.icon("#9A9AAF")}

@ -1,10 +1,10 @@
import { import {
Box, Box,
Typography, Typography,
RadioGroup, RadioGroup,
FormControlLabel, FormControlLabel,
Radio, Radio,
useTheme, useTheme, useMediaQuery,
} from "@mui/material"; } from "@mui/material";
import gag from "./gag.png" import gag from "./gag.png"
@ -27,6 +27,7 @@ export const Varimg = ({ currentQuestion }: VarimgProps) => {
const mode = modes; const mode = modes;
const quiz = useCurrentQuiz(); const quiz = useCurrentQuiz();
const theme = useTheme(); const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(650));
const { answer } = const { answer } =
answers.find( answers.find(
({ questionId }) => questionId === currentQuestion.content.id ({ questionId }) => questionId === currentQuestion.content.id
@ -38,7 +39,13 @@ export const Varimg = ({ currentQuestion }: VarimgProps) => {
return ( return (
<Box> <Box>
<Typography variant="h5" color={theme.palette.text.primary}>{currentQuestion.title}</Typography> <Typography variant="h5" color={theme.palette.text.primary}>{currentQuestion.title}</Typography>
<Box sx={{ display: "flex", marginTop: "20px" }}> <Box sx={{
display: "flex",
marginTop: "20px",
flexDirection: isMobile ? "column-reverse" : undefined,
gap: isMobile ? "30px" : undefined
}}>
<RadioGroup <RadioGroup
name={currentQuestion.id} name={currentQuestion.id}
value={currentQuestion.content.variants.findIndex( value={currentQuestion.content.variants.findIndex(
@ -52,7 +59,7 @@ export const Varimg = ({ currentQuestion }: VarimgProps) => {
flexBasis: "100%", flexBasis: "100%",
}} }}
> >
<Box sx={{ display: "flex", flexDirection: "column", width: "100%" }}> <Box sx={{ display: "flex", flexDirection: "column", width: "100%", gap: isMobile ? "20px" : undefined }}>
{currentQuestion.content.variants.map((variant, index) => ( {currentQuestion.content.variants.map((variant, index) => (
<FormControlLabel <FormControlLabel
key={variant.id} key={variant.id}
@ -65,6 +72,7 @@ export const Varimg = ({ currentQuestion }: VarimgProps) => {
border: `1px solid`, border: `1px solid`,
borderColor: answer === variant.id ? theme.palette.primary.main : "#9A9AAF", borderColor: answer === variant.id ? theme.palette.primary.main : "#9A9AAF",
display: "flex", display: "flex",
margin: isMobile ? 0 : undefined,
}} }}
value={index} value={index}
onClick={(event) => { onClick={(event) => {
@ -113,7 +121,7 @@ export const Varimg = ({ currentQuestion }: VarimgProps) => {
alt="" alt=""
/> />
: :
(variant?.extendedText || "Выберите вариант ответа слева") (variant?.extendedText || isMobile ? ("Выберите вариант ответа ниже") : ("Выберите вариант ответа слева"))
} }
</Box> </Box>