Merge branch 'rel' into 'main'

Rel

See merge request frontend/squiz!101
This commit is contained in:
Nastya 2023-12-30 01:38:45 +00:00
commit e21d96f721
11 changed files with 341 additions and 204 deletions

@ -5,7 +5,7 @@ import "dayjs/locale/ru";
import SigninDialog from "./pages/auth/Signin";
import SignupDialog from "./pages/auth/Signup";
import { ViewPage } from "./pages/ViewPublicationPage";
import { DesignPage } from "./pages/startPage/DesignPage";
import { DesignPage } from "./pages/DesignPage/DesignPage";
import { Route, Routes, useLocation, useNavigate, Navigate } from "react-router-dom";
import "./index.css";
import ContactFormPage from "./pages/ContactFormPage/ContactFormPage";

@ -0,0 +1,23 @@
import {Box} from "@mui/material";
interface Color{
color?: string
}
export default function ColorRingIcon({color = "#333647"}: Color) {
return (
<Box
sx={{
height: "20px",
width: "20px",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
<svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="0.5" y="0.5" width="16" height="16" rx="8" fill={color} stroke="#9A9AAF"/>
</svg>
</Box>
)
}

@ -0,0 +1,118 @@
import {Box, ButtonBase, IconButton, Paper, Typography, useMediaQuery, useTheme} from "@mui/material";
import ColorRingIcon from "./ColorRingIcon";
import {updateQuiz} from "@root/quizes/actions";
import {useCurrentQuiz} from "@root/quizes/hooks";
import {toggleQuizPreview} from "@root/quizPreview";
import VisibilityIcon from "@mui/icons-material/Visibility";
import React from "react";
export const DesignFilling = () => {
const quiz = useCurrentQuiz();
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(830));
const ButtonsThemeLight = [
["Стандартный", "StandardTheme", "#7E2AEA", "#FFFFFF"],
["Черно-белый", "BlackWhiteTheme", "#4E4D51", "#FFFFFF"],
["Оливковый", "OliveTheme", "#758E4F", "#F9FBF1"],
["Фиолетовый", "PurpleTheme", "#7E2AEA", "#FBF8FF"],
["Желтый", "YellowTheme", "#F2B133", "#FFFCF6"],
["Голубой", "BlueTheme", "#4964ED", "#F5F7FF"],
["Розовый", "PinkTheme", "#D34085", "#FFF9FC"]
]
const ButtonsThemeDark = [
["Стандартный", "StandardDarkTheme", "#7E2AEA", "#FFFFFF"],
["Золотой", "GoldDarkTheme", "#E6AA37", "#FFFFFF"],
["Розовый", "PinkDarkTheme", "#D34085", "#FFFFFF"],
["Бирюзовый", "BlueDarkTheme", "#07A0C3", "#FFFFFF"],
]
return (
<Box sx={{width: "100%", padding: "25px"}}>
<Typography variant="h5" sx={{marginBottom: "40px"}}>Дизайн</Typography>
<Paper sx={{
padding: "20px",
maxWidth: "796px",
width: "100%",
display: "flex",
gap: "20px",
borderRadius: "12px",
flexWrap: "wrap"
}}>
<Box
sx={{width: isMobile ? "100%" : "48%", display: "flex", flexDirection: "column", gap: "12px"}}
>
<Typography color={"#9A9AAF"}>Со светлым фоном</Typography>
{ButtonsThemeLight.map((e, i) => (
<ButtonBase
sx={{
maxWidth: "368px",
width: "100%",
padding: "22px 21px",
background: quiz.config.theme == e[1] ? "linear-gradient(0deg, rgba(126, 42, 234, 0.10) 0%, rgba(126, 42, 234, 0.10) 100%)" : "#F2F3F7",
borderRadius: "12px",
justifyContent: "space-between",
border: quiz.config.theme == e[1] ? "1px solid #7E2AEA" : "none"
}}
key={i}
value={e[1]}
onClick={() => updateQuiz(quiz.id, (quiz) => {
quiz.config.theme = e[1]})}
>
<Typography color={"#4D4D4D"}>{e[0]}</Typography>
<Box sx={{display: "flex", gap: "7px",}}>
<ColorRingIcon color={e[2]}/>
<ColorRingIcon/>
<ColorRingIcon color={e[3]}/>
</Box>
</ButtonBase>
))}
</Box>
<Box
sx={{width: isMobile ? "100%" : "48%", display: "flex", flexDirection: "column", gap: "12px"}}
>
<Typography color={"#9A9AAF"}>С тёмным фоном</Typography>
{ButtonsThemeDark.map((e, i) => (
<ButtonBase
sx={{
maxWidth: "368px",
width: "100%",
padding: "22px 21px",
background: quiz.config.theme == e[1] ? "linear-gradient(0deg, rgba(126, 42, 234, 0.10) 0%, rgba(126, 42, 234, 0.10) 100%)" : "#F2F3F7",
borderRadius: "12px",
justifyContent: "space-between",
border: quiz.config.theme == e[1] ? "1px solid #7E2AEA" : "none"
}}
key={i}
value={e[1]}
onClick={() => updateQuiz(quiz.id, (quiz) => {
quiz.config.theme = e[1]})}
>
<Typography color={"#4D4D4D"}>{e[0]}</Typography>
<Box sx={{display: "flex", gap: "7px",}}>
<ColorRingIcon color={e[2]}/>
<ColorRingIcon color={e[3]}/>
<ColorRingIcon />
</Box>
</ButtonBase>
))}
</Box>
</Paper>
<Box sx={{textAlign: "end"}}>
<IconButton
onClick={toggleQuizPreview}
sx={{
pointerEvents: "auto",
marginLeft: "auto",
position: "relative",
zIndex: "999999",
alignItems: "end"
}}
>
<VisibilityIcon sx={{ height: "30px", width: "30px" }} />
</IconButton>
</Box>
</Box>
);
}

@ -1,5 +1,5 @@
import { quizApi } from "@api/quiz";
import { Box, useMediaQuery, useTheme } from "@mui/material";
import {Box, IconButton, useMediaQuery, useTheme} from "@mui/material";
import {
resetEditConfig,
setQuizes,
@ -10,10 +10,10 @@ import { useCurrentQuiz } from "@root/quizes/hooks";
import { useQuizStore } from "@root/quizes/store";
import Sidebar from "@ui_kit/Sidebar";
import { enqueueSnackbar } from "notistack";
import { useEffect, useState } from "react";
import React, { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import { useDebouncedCallback } from "use-debounce";
import { SidebarMobile } from "./Sidebar/SidebarMobile";
import { SidebarMobile } from "../startPage/Sidebar/SidebarMobile";
import {
cleanQuestions,
createResult,
@ -33,10 +33,15 @@ 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";
import { ConfirmLeaveModal } from "./ConfirmLeaveModal";
import { ModalInfoWhyCantCreate } from "../startPage/ModalInfoWhyCantCreate";
import { ConfirmLeaveModal } from "../startPage/ConfirmLeaveModal";
import { checkQuestionHint } from "@utils/checkQuestionHint";
import { Header } from "./Header";
import { Header } from "../startPage/Header";
import {DesignFilling} from "./DesignFilling";
import {toggleQuizPreview} from "@root/quizPreview";
import VisibilityIcon from "@mui/icons-material/Visibility";
import {createPortal} from "react-dom";
import QuizPreview from "@ui_kit/QuizPreview/QuizPreview";
export const DesignPage = () => {
const quiz = useCurrentQuiz();
@ -47,7 +52,10 @@ export const DesignPage = () => {
const getData = async () => {
const quizes = await quizApi.getList();
setQuizes(quizes);
if (editQuizId) {
const questions = await questionApi.getList({ quiz_id: editQuizId });
setQuestions(questions);
}
};
getData();
}, []);
@ -71,6 +79,7 @@ export const DesignPage = () => {
useEffect(() => {
if (editQuizId === null) navigate("/list");
}, [navigate, editQuizId]);
const followNewPage = () => {
@ -95,13 +104,14 @@ export const DesignPage = () => {
return (
<>
<Header setMobileSidebar={setMobileSidebar} />
<Box sx={{ display: "flex" }}>
<Box sx={{ display: "flex", flexDirection: isMobile ? "column" : "row" }}>
{isMobile ? (
<SidebarMobile open={mobileSidebar} changePage={changePage} />
) : (
<Sidebar changePage={changePage} />
)}
<Box>Страница дизайна</Box>
<DesignFilling/>
{createPortal(<QuizPreview />, document.body)}
</Box>
<ModalInfoWhyCantCreate />
<ConfirmLeaveModal

@ -111,55 +111,55 @@ export const UploadImageModal: React.FC<ModalkaProps> = ({
</Box>
</Box>
</ButtonBase>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
margin: "20px 0",
}}
>
<Typography
sx={{
fontWeight: "bold",
color: "#4D4D4D",
}}
>
Или выберите на фотостоке
</Typography>
<img src={UnsplashIcon} alt="" />
</Box>
<TextField
id="search-in-unsplash"
placeholder="Ищите изображения на английском языка"
sx={{
"& .MuiInputBase-input": {
height: "48px",
padding: "0 10px 0 0",
},
"& .MuiOutlinedInput-notchedOutline": {
borderRadius: "8px",
},
"& .Mui-focused .MuiOutlinedInput-notchedOutline": {
border: "1px solid rgba(0, 0, 0, 0.23)",
},
"& .MuiInputBase-root.MuiOutlinedInput-root .MuiOutlinedInput-notchedOutline": {
borderColor: "rgba(0, 0, 0, 0.23)",
},
}}
InputProps={{
startAdornment: (
<InputAdornment
position="start"
sx={{
outline: "none",
"& svg > path": { stroke: "#9A9AAF" },
}}
>
<SearchIcon />
</InputAdornment>
),
}}
/>
{/* <Box*/}
{/* sx={{*/}
{/* display: "flex",*/}
{/* justifyContent: "space-between",*/}
{/* margin: "20px 0",*/}
{/* }}*/}
{/* >*/}
{/* <Typography*/}
{/* sx={{*/}
{/* fontWeight: "bold",*/}
{/* color: "#4D4D4D",*/}
{/* }}*/}
{/* >*/}
{/* Или выберите на фотостоке*/}
{/* </Typography>*/}
{/* <img src={UnsplashIcon} alt="" />*/}
{/* </Box>*/}
{/* <TextField*/}
{/* id="search-in-unsplash"*/}
{/* placeholder="Ищите изображения на английском языка"*/}
{/* sx={{*/}
{/* "& .MuiInputBase-input": {*/}
{/* height: "48px",*/}
{/* padding: "0 10px 0 0",*/}
{/* },*/}
{/* "& .MuiOutlinedInput-notchedOutline": {*/}
{/* borderRadius: "8px",*/}
{/* },*/}
{/* "& .Mui-focused .MuiOutlinedInput-notchedOutline": {*/}
{/* border: "1px solid rgba(0, 0, 0, 0.23)",*/}
{/* },*/}
{/* "& .MuiInputBase-root.MuiOutlinedInput-root .MuiOutlinedInput-notchedOutline": {*/}
{/* borderColor: "rgba(0, 0, 0, 0.23)",*/}
{/* },*/}
{/* }}*/}
{/* InputProps={{*/}
{/* startAdornment: (*/}
{/* <InputAdornment*/}
{/* position="start"*/}
{/* sx={{*/}
{/* outline: "none",*/}
{/* "& svg > path": { stroke: "#9A9AAF" },*/}
{/* }}*/}
{/* >*/}
{/* <SearchIcon />*/}
{/* </InputAdornment>*/}
{/* ),*/}
{/* }}*/}
{/* />*/}
</Box>
</Box>
</Modal>

@ -36,65 +36,65 @@ export default function ResponseSettings({ question }: Props) {
marginRight: isFigmaTablte ? (isMobile ? "0" : "0px") : "30px",
}}
>
<Box
sx={{
pt: isMobile ? "25px" : "20px",
pb: isMobile ? "25px" : "20px",
pl: "20px",
display: "flex",
flexDirection: "column",
gap: "14px",
width: "100%",
}}
>
<Typography
sx={{
height: isMobile ? "18px" : "auto",
fontWeight: "500",
fontSize: "18px",
color: " #4D4D4D",
}}
>
Настройки ответов
</Typography>
{/* <CustomCheckbox
sx={{ mr: isMobile ? "0px" : "16px" }}
label={"Длинный текстовый ответ"}
checked={question.content.largeCheck}
handleChange={({ target }) => {
updateQuestion(question.id, (question) => {
if (!("largeCheck" in question.content)) return;
question.content.largeCheck = target.checked;
});
}}
/> */}
<CustomCheckbox
sx={{ mr: isMobile ? "0px" : "16px" }}
label={"Можно несколько"}
checked={question.content.multi}
dataCy="multiple-answers-checkbox"
handleChange={({ target }) => {
updateQuestion(question.id, (question) => {
if (!("multi" in question.content)) return;
question.content.multi = target.checked;
});
}}
/>
{/* <CustomCheckbox
sx={{ mr: isMobile ? "0px" : "16px" }}
label={'Вариант "свой ответ"'}
checked={question.content.own}
handleChange={({ target }) => {
updateQuestion(question.id, (question) => {
if (!("own" in question.content)) return;
question.content.own = target.checked;
});
}}
/> */}
</Box>
{/*<Box*/}
{/* sx={{*/}
{/* pt: isMobile ? "25px" : "20px",*/}
{/* pb: isMobile ? "25px" : "20px",*/}
{/* pl: "20px",*/}
{/* display: "flex",*/}
{/* flexDirection: "column",*/}
{/* gap: "14px",*/}
{/* width: "100%",*/}
{/* }}*/}
{/*>*/}
{/* <Typography*/}
{/* sx={{*/}
{/* height: isMobile ? "18px" : "auto",*/}
{/* fontWeight: "500",*/}
{/* fontSize: "18px",*/}
{/* color: " #4D4D4D",*/}
{/* }}*/}
{/* >*/}
{/* Настройки ответов*/}
{/* </Typography>*/}
{/* <CustomCheckbox*/}
{/* sx={{ mr: isMobile ? "0px" : "16px" }}*/}
{/* label={"Длинный текстовый ответ"}*/}
{/* checked={question.content.largeCheck}*/}
{/* handleChange={({ target }) => {*/}
{/* updateQuestion(question.id, (question) => {*/}
{/* if (!("largeCheck" in question.content)) return;*/}
{/* */}
{/* question.content.largeCheck = target.checked;*/}
{/* });*/}
{/* }}*/}
{/* />*/}
{/* <CustomCheckbox*/}
{/* sx={{ mr: isMobile ? "0px" : "16px" }}*/}
{/* label={"Можно несколько"}*/}
{/* checked={question.content.multi}*/}
{/* dataCy="multiple-answers-checkbox"*/}
{/* handleChange={({ target }) => {*/}
{/* updateQuestion(question.id, (question) => {*/}
{/* if (!("multi" in question.content)) return;*/}
{/* */}
{/* question.content.multi = target.checked;*/}
{/* });*/}
{/* }}*/}
{/* />*/}
{/* <CustomCheckbox*/}
{/* sx={{ mr: isMobile ? "0px" : "16px" }}*/}
{/* label={'Вариант "свой ответ"'}*/}
{/* checked={question.content.own}*/}
{/* handleChange={({ target }) => {*/}
{/* updateQuestion(question.id, (question) => {*/}
{/* if (!("own" in question.content)) return;*/}
{/* */}
{/* question.content.own = target.checked;*/}
{/* });*/}
{/* }}*/}
{/* /> */}
{/*</Box>*/}
<Box
sx={{
boxSizing: "border-box",

@ -64,41 +64,6 @@ export const ViewPage = () => {
) : (
<Question questions={filteredQuestions} />
)}
<Box>
<Button onClick={() => updateQuiz(quiz.id, (quiz) => {
quiz.config.theme = "StandardTheme"
})}>Standard</Button>
<Button onClick={() => updateQuiz(quiz.id, (quiz) => {
quiz.config.theme = "PinkTheme"
})}>Pink</Button>
<Button onClick={() => updateQuiz(quiz.id, (quiz) => {
quiz.config.theme = "BlackWhiteTheme"
})}>BlackWhite</Button>
<Button onClick={() => updateQuiz(quiz.id, (quiz) => {
quiz.config.theme = "OliveTheme"
})}>Olive</Button>
<Button onClick={() => updateQuiz(quiz.id, (quiz) => {
quiz.config.theme = "YellowTheme"
})}>Yellow</Button>
<Button onClick={() => updateQuiz(quiz.id, (quiz) => {
quiz.config.theme = "PurpleTheme"
})}>Purple</Button>
<Button onClick={() => updateQuiz(quiz.id, (quiz) => {
quiz.config.theme = "BlueTheme"
})}>Blue</Button>
<Button onClick={() => updateQuiz(quiz.id, (quiz) => {
quiz.config.theme = "StandardDarkTheme"
})}>StandardDark</Button>
<Button onClick={() => updateQuiz(quiz.id, (quiz) => {
quiz.config.theme = "PinkDarkTheme"
})}>PinkDark</Button>
<Button onClick={() => updateQuiz(quiz.id, (quiz) => {
quiz.config.theme = "GoldDarkTheme"
})}>GoldDark</Button>
<Button onClick={() => updateQuiz(quiz.id, (quiz) => {
quiz.config.theme = "BlueDarkTheme"
})}>BlueDark</Button>
</Box>
</Box>
</ThemeProvider>

@ -73,7 +73,7 @@ export const Number = ({ currentQuestion }: NumberProps) => {
width: "100%",
marginTop: "20px",
gap: "30px",
paddingRight: isMobile ? "10px" : undefined
paddingRight: "10px"
}}
>
<CustomSlider

@ -1,5 +1,5 @@
import { FC, useState } from "react";
import { Box, Typography } from "@mui/material";
import {Box, Popper, Typography} from "@mui/material";
import { People } from "@mui/icons-material";
import { SidebarModal } from "./SidebarModal";
@ -11,6 +11,7 @@ import { Question } from "./icons/Question";
import { Settings } from "./icons/Settings";
import { Pencil } from "./icons/Pencil";
import { ArrowDown } from "./icons/ArrowDown";
import Sidebar from "@ui_kit/Sidebar";
interface Iprops {
open: boolean;
@ -30,11 +31,15 @@ const quizSetupSteps = [
] as const;
export const SidebarMobile: FC<Iprops> = ({ open, changePage }) => {
const [openModal, setOpenModal] = useState<boolean>(false);
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const handleClick = (event) => {
setAnchorEl(anchorEl ? null : event.currentTarget);
};
const openPopper = Boolean(anchorEl);
const id = openPopper ? 'simple-popper' : undefined;
const onClose = () => {
setOpenModal(false);
};
return (
<Box
@ -76,32 +81,33 @@ export const SidebarMobile: FC<Iprops> = ({ open, changePage }) => {
<Box
sx={{
width: "100%",
justifyContent: "center",
justifyContent: "end",
display: "flex",
marginTop: "20px",
flexWrap: "wrap",
gap: "5px",
}}
>
{quizSetupSteps.map(({ sidebarIcon }, index) => (
<Box
onClick={() => changePage(index)}
sx={{
cursor: "pointer",
width: "44px",
height: "44px",
background: "#262835",
display: "flex",
justifyContent: "center",
alignItems: "center",
borderRadius: "8px",
}}
>
{sidebarIcon}
</Box>
))}
{/*{quizSetupSteps.map(({ sidebarIcon }, index) => (*/}
{/* <Box*/}
{/* onClick={() => changePage(index)}*/}
{/* sx={{*/}
{/* cursor: "pointer",*/}
{/* width: "44px",*/}
{/* height: "44px",*/}
{/* background: "#262835",*/}
{/* display: "flex",*/}
{/* justifyContent: "center",*/}
{/* alignItems: "center",*/}
{/* borderRadius: "8px",*/}
{/* }}*/}
{/* >*/}
{/* {sidebarIcon}*/}
{/* </Box>*/}
{/*))}*/}
<Box
onClick={() => setOpenModal(true)}
aria-describedby={id}
onClick={handleClick}
sx={{
px: "10px",
width: "70px",
@ -121,7 +127,7 @@ export const SidebarMobile: FC<Iprops> = ({ open, changePage }) => {
<ArrowDown style={{ color: "#F2F3F7" }} />
</Box>
</Box>
<SidebarModal open={openModal} onClose={onClose} changePage={changePage} />
<SidebarModal open={openPopper} anchorEl={anchorEl} handleClick={handleClick} id={id} changePage={changePage} />
</Box>
);
};

@ -1,39 +1,39 @@
import { Box, Modal } from "@mui/material";
import {Box, Modal, Popper} from "@mui/material";
import Sidebar from "@ui_kit/Sidebar";
type SidebarModalProps = {
open: boolean;
onClose: () => void;
handleClick: () => void;
changePage: (step: number) => void;
anchorEl: HTMLElement;
id: string;
};
export const SidebarModal = ({
open,
onClose,
handleClick,
changePage,
id,
anchorEl
}: SidebarModalProps) => {
return (
<Modal open={open} onClose={onClose}>
<Box
onClick={onClose}
sx={{
outline: "none",
position: "absolute",
overflow: "hidden",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
maxWidth: "230px",
maxHeight: "400px",
width: "100%",
bgcolor: "background.paper",
borderRadius: "5px",
boxShadow: 24,
p: 0,
}}
>
<Sidebar changePage={changePage} disableCollapse />
</Box>
</Modal>
<Popper open={open} id={id} anchorEl={anchorEl}>
<Box
onClick={handleClick}
sx={{
outline: "none",
overflow: "hidden",
maxWidth: "230px",
maxHeight: "400px",
width: "100%",
bgcolor: "background.paper",
borderRadius: "5px",
boxShadow: 24,
p: 0,
}}
>
<Sidebar changePage={changePage} disableCollapse />
</Box>
</Popper>
);
};

@ -5,10 +5,13 @@ import { QuizStartpageAlignType, QuizStartpageType } from "@model/quizSettings";
import { notReachable } from "../../utils/notReachable";
import { useUADevice } from "../../utils/hooks/useUADevice";
import {useEffect, useRef, useState} from "react";
import {NameplateLogo} from "@icons/NameplateLogo";
import {modes} from "@utils/themes/Publication/themePublication";
export default function QuizPreviewLayout() {
const theme = useTheme();
const quiz = useCurrentQuiz();
const mode = modes;
const { isMobileDevice } = useUADevice();
if (!quiz) return null;
@ -124,6 +127,18 @@ export default function QuizPreviewLayout() {
)}
<Typography sx={{ fontSize: "12px" }}>{quiz.config.info.law}</Typography>
</Box>
<Box
sx={{
display: "flex",
alignItems: "center",
gap: "10px"
}}
>
<NameplateLogo style={{ fontSize: "30px", color: quiz.config.startpageType === "expanded" ? "#FFFFFF" : (mode[quiz.config.theme] ? "#151515" : "#FFFFFF") }} />
<Typography sx={{ fontSize: "16px", color: quiz.config.startpageType === "expanded" ? "#F5F7FF" : (mode[quiz.config.theme] ? "#4D4D4D" : "#F5F7FF"), whiteSpace: "nowrap", }}>
Сделано на PenaQuiz
</Typography>
</Box>
</>
}
backgroundBlock={background}