add using video embeds by url
This commit is contained in:
parent
f516897dad
commit
b41251966a
@ -7,7 +7,7 @@
|
|||||||
"@emotion/react": "^11.10.5",
|
"@emotion/react": "^11.10.5",
|
||||||
"@emotion/styled": "^11.10.5",
|
"@emotion/styled": "^11.10.5",
|
||||||
"@frontend/kitui": "^1.0.82",
|
"@frontend/kitui": "^1.0.82",
|
||||||
"@frontend/squzanswerer": "^1.0.44",
|
"@frontend/squzanswerer": "^1.0.45",
|
||||||
"@mui/icons-material": "^5.10.14",
|
"@mui/icons-material": "^5.10.14",
|
||||||
"@mui/material": "^5.10.14",
|
"@mui/material": "^5.10.14",
|
||||||
"@mui/x-charts": "^6.19.5",
|
"@mui/x-charts": "^6.19.5",
|
||||||
|
@ -12,7 +12,7 @@ export interface QuizQuestionPage extends QuizQuestionBase {
|
|||||||
picture: string;
|
picture: string;
|
||||||
originalPicture: string;
|
originalPicture: string;
|
||||||
useImage: boolean;
|
useImage: boolean;
|
||||||
video: string;
|
video: string | null;
|
||||||
hint: QuestionHint;
|
hint: QuestionHint;
|
||||||
rule: PreviewRule;
|
rule: PreviewRule;
|
||||||
back: string;
|
back: string;
|
||||||
|
@ -1,8 +1,4 @@
|
|||||||
import type {
|
import type { QuizQuestionBase, QuestionBranchingRule, QuestionHint } from "./shared";
|
||||||
QuizQuestionBase,
|
|
||||||
QuestionBranchingRule,
|
|
||||||
QuestionHint,
|
|
||||||
} from "./shared";
|
|
||||||
|
|
||||||
export interface QuizQuestionResult extends QuizQuestionBase {
|
export interface QuizQuestionResult extends QuizQuestionBase {
|
||||||
type: "result";
|
type: "result";
|
||||||
@ -10,7 +6,7 @@ export interface QuizQuestionResult extends QuizQuestionBase {
|
|||||||
id: string;
|
id: string;
|
||||||
back: string;
|
back: string;
|
||||||
originalBack: string;
|
originalBack: string;
|
||||||
video: string;
|
video: string | null;
|
||||||
innerName: string;
|
innerName: string;
|
||||||
text: string;
|
text: string;
|
||||||
price: [number] | [number, number];
|
price: [number] | [number, number];
|
||||||
|
@ -1,18 +1,5 @@
|
|||||||
import {
|
import { Box, Button, IconButton, Modal, Typography, useMediaQuery, useTheme } from "@mui/material";
|
||||||
Box,
|
import { copyQuestion, deleteQuestion, deleteQuestionWithTimeout, updateQuestion } from "@root/questions/actions";
|
||||||
Button,
|
|
||||||
IconButton,
|
|
||||||
Modal,
|
|
||||||
Typography,
|
|
||||||
useMediaQuery,
|
|
||||||
useTheme,
|
|
||||||
} from "@mui/material";
|
|
||||||
import {
|
|
||||||
copyQuestion,
|
|
||||||
deleteQuestion,
|
|
||||||
deleteQuestionWithTimeout,
|
|
||||||
updateQuestion,
|
|
||||||
} from "@root/questions/actions";
|
|
||||||
import CustomTextField from "@ui_kit/CustomTextField";
|
import CustomTextField from "@ui_kit/CustomTextField";
|
||||||
|
|
||||||
import { CopyIcon } from "@icons/questionsPage/CopyIcon";
|
import { CopyIcon } from "@icons/questionsPage/CopyIcon";
|
||||||
@ -71,7 +58,7 @@ export default function PageOptions({ disableInput, question }: Props) {
|
|||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<MediaSelectionAndDisplay
|
<MediaSelectionAndDisplay
|
||||||
resultData={question}
|
question={question}
|
||||||
cropAspectRatio={{ width: 1388.8, height: 793.2 }}
|
cropAspectRatio={{ width: 1388.8, height: 793.2 }}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
@ -107,16 +94,17 @@ export default function PageOptions({ disableInput, question }: Props) {
|
|||||||
if (question.content.rule.parentId.length !== 0) {
|
if (question.content.rule.parentId.length !== 0) {
|
||||||
setOpenDelete(true);
|
setOpenDelete(true);
|
||||||
} else {
|
} else {
|
||||||
deleteQuestionWithTimeout(question.id, () =>
|
deleteQuestionWithTimeout(question.id, () => DeleteFunction(question.id));
|
||||||
DeleteFunction(question.id),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
data-cy="delete-question"
|
data-cy="delete-question"
|
||||||
>
|
>
|
||||||
<DeleteIcon color={"#4D4D4D"} />
|
<DeleteIcon color={"#4D4D4D"} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<Modal open={openDelete} onClose={() => setOpenDelete(false)}>
|
<Modal
|
||||||
|
open={openDelete}
|
||||||
|
onClose={() => setOpenDelete(false)}
|
||||||
|
>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
@ -128,10 +116,12 @@ export default function PageOptions({ disableInput, question }: Props) {
|
|||||||
background: "#FFFFFF",
|
background: "#FFFFFF",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography variant="h6" sx={{ textAlign: "center" }}>
|
<Typography
|
||||||
Вы удаляете вопрос, участвующий в ветвлении. Все его потомки
|
variant="h6"
|
||||||
потеряют данные ветвления. Вы уверены, что хотите удалить
|
sx={{ textAlign: "center" }}
|
||||||
вопрос?
|
>
|
||||||
|
Вы удаляете вопрос, участвующий в ветвлении. Все его потомки потеряют данные ветвления. Вы уверены, что
|
||||||
|
хотите удалить вопрос?
|
||||||
</Typography>
|
</Typography>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
@ -152,9 +142,7 @@ export default function PageOptions({ disableInput, question }: Props) {
|
|||||||
variant="contained"
|
variant="contained"
|
||||||
sx={{ minWidth: "150px" }}
|
sx={{ minWidth: "150px" }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
deleteQuestionWithTimeout(question.id, () =>
|
deleteQuestionWithTimeout(question.id, () => DeleteFunction(question.id));
|
||||||
DeleteFunction(question.id),
|
|
||||||
);
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Подтвердить
|
Подтвердить
|
||||||
|
@ -1,16 +1,8 @@
|
|||||||
import {
|
import { Box, Button, ButtonBase, Dialog, Typography, useTheme } from "@mui/material";
|
||||||
Box,
|
|
||||||
Button,
|
|
||||||
ButtonBase,
|
|
||||||
Modal,
|
|
||||||
Typography,
|
|
||||||
useTheme,
|
|
||||||
} from "@mui/material";
|
|
||||||
import SelectableButton from "@ui_kit/SelectableButton";
|
|
||||||
import CustomTextField from "@ui_kit/CustomTextField";
|
import CustomTextField from "@ui_kit/CustomTextField";
|
||||||
|
import SelectableButton from "@ui_kit/SelectableButton";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import UploadIcon from "../../assets/icons/UploadIcon";
|
import UploadIcon from "../../assets/icons/UploadIcon";
|
||||||
|
|
||||||
import type { DragEvent } from "react";
|
import type { DragEvent } from "react";
|
||||||
|
|
||||||
type BackgroundTypeModal = "linkVideo" | "ownVideo";
|
type BackgroundTypeModal = "linkVideo" | "ownVideo";
|
||||||
@ -18,18 +10,12 @@ type BackgroundTypeModal = "linkVideo" | "ownVideo";
|
|||||||
type HelpQuestionsProps = {
|
type HelpQuestionsProps = {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
video: string;
|
video: string | null;
|
||||||
onUpload: (number: string) => void;
|
onUpload: (number: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const UploadVideoModal = ({
|
export default function UploadVideoModal({ open, onClose, video, onUpload }: HelpQuestionsProps) {
|
||||||
open,
|
const [backgroundTypeModal, setBackgroundTypeModal] = useState<BackgroundTypeModal>("linkVideo");
|
||||||
onClose,
|
|
||||||
video,
|
|
||||||
onUpload,
|
|
||||||
}: HelpQuestionsProps) => {
|
|
||||||
const [backgroundTypeModal, setBackgroundTypeModal] =
|
|
||||||
useState<BackgroundTypeModal>("linkVideo");
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
const handleDrop = (event: DragEvent<HTMLDivElement>) => {
|
const handleDrop = (event: DragEvent<HTMLDivElement>) => {
|
||||||
@ -42,24 +28,17 @@ export const UploadVideoModal = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Dialog
|
||||||
open={open}
|
open={open}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
aria-labelledby="modal-modal-title"
|
PaperProps={{
|
||||||
aria-describedby="modal-modal-description"
|
sx: {
|
||||||
>
|
maxWidth: "640px",
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
position: "absolute",
|
|
||||||
top: "50%",
|
|
||||||
left: "50%",
|
|
||||||
transform: "translate(-50%, -50%)",
|
|
||||||
maxWidth: "690px",
|
|
||||||
bgcolor: "background.paper",
|
|
||||||
borderRadius: "12px",
|
borderRadius: "12px",
|
||||||
boxShadow: 24,
|
boxShadow: 24,
|
||||||
p: 0,
|
p: 0,
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
@ -70,10 +49,12 @@ export const UploadVideoModal = ({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography sx={{ color: "#9A9AAF" }}>
|
<Typography sx={{ color: "#9A9AAF" }}>
|
||||||
Видео можно вставить с любого хостинга: YouTube, Vimeo или загрузить
|
Видео можно вставить с любого хостинга: YouTube, Vimeo или загрузить собственное
|
||||||
собственное
|
|
||||||
</Typography>
|
</Typography>
|
||||||
<Button onClick={onClose} variant="contained">
|
<Button
|
||||||
|
onClick={onClose}
|
||||||
|
variant="contained"
|
||||||
|
>
|
||||||
Готово
|
Готово
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
@ -95,20 +76,16 @@ export const UploadVideoModal = ({
|
|||||||
</Box>
|
</Box>
|
||||||
{backgroundTypeModal === "linkVideo" ? (
|
{backgroundTypeModal === "linkVideo" ? (
|
||||||
<Box sx={{ padding: "20px" }}>
|
<Box sx={{ padding: "20px" }}>
|
||||||
<Typography sx={{ paddingBottom: "15px", fontWeight: "500" }}>
|
<Typography sx={{ paddingBottom: "15px", fontWeight: "500" }}>Ссылка на видео</Typography>
|
||||||
Ссылка на видео
|
|
||||||
</Typography>
|
|
||||||
<CustomTextField
|
<CustomTextField
|
||||||
placeholder={"http://example.com"}
|
placeholder={"http://example.com"}
|
||||||
text={video}
|
value={video || ""}
|
||||||
onChange={({ target }) => onUpload(target.value || " ")}
|
onChange={({ target }) => onUpload(target.value || " ")}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
) : (
|
) : (
|
||||||
<Box sx={{ padding: "20px" }}>
|
<Box sx={{ padding: "20px" }}>
|
||||||
<Typography sx={{ paddingBottom: "15px", fontWeight: "500" }}>
|
<Typography sx={{ paddingBottom: "15px", fontWeight: "500" }}>Загрузите видео</Typography>
|
||||||
Загрузите видео
|
|
||||||
</Typography>
|
|
||||||
<ButtonBase
|
<ButtonBase
|
||||||
component="label"
|
component="label"
|
||||||
sx={{ justifyContent: "flex-start", width: "100%" }}
|
sx={{ justifyContent: "flex-start", width: "100%" }}
|
||||||
@ -125,9 +102,7 @@ export const UploadVideoModal = ({
|
|||||||
type="file"
|
type="file"
|
||||||
/>
|
/>
|
||||||
<Box
|
<Box
|
||||||
onDragOver={(event: DragEvent<HTMLDivElement>) =>
|
onDragOver={(event: DragEvent<HTMLDivElement>) => event.preventDefault()}
|
||||||
event.preventDefault()
|
|
||||||
}
|
|
||||||
onDrop={handleDrop}
|
onDrop={handleDrop}
|
||||||
sx={{
|
sx={{
|
||||||
width: "580px",
|
width: "580px",
|
||||||
@ -142,18 +117,13 @@ export const UploadVideoModal = ({
|
|||||||
>
|
>
|
||||||
<UploadIcon />
|
<UploadIcon />
|
||||||
<Box sx={{ color: "#9A9AAF" }}>
|
<Box sx={{ color: "#9A9AAF" }}>
|
||||||
<Typography sx={{ fontWeight: "500" }}>
|
<Typography sx={{ fontWeight: "500" }}>Добавить видео</Typography>
|
||||||
Добавить видео
|
<Typography sx={{ fontSize: "16px" }}>Принимает .mp4 и .mov формат — максимум 100мб</Typography>
|
||||||
</Typography>
|
|
||||||
<Typography sx={{ fontSize: "16px" }}>
|
|
||||||
Принимает .mp4 и .mov формат — максимум 100мб
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Dialog>
|
||||||
</Modal>
|
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
@ -5,7 +5,7 @@ import SelectableButton from "@ui_kit/SelectableButton";
|
|||||||
import UploadBox from "@ui_kit/UploadBox";
|
import UploadBox from "@ui_kit/UploadBox";
|
||||||
import { memo, useState } from "react";
|
import { memo, useState } from "react";
|
||||||
import UploadIcon from "../../assets/icons/UploadIcon";
|
import UploadIcon from "../../assets/icons/UploadIcon";
|
||||||
import { UploadVideoModal } from "./UploadVideoModal";
|
import UploadVideoModal from "./UploadVideoModal";
|
||||||
|
|
||||||
type BackgroundType = "text" | "video";
|
type BackgroundType = "text" | "video";
|
||||||
|
|
||||||
@ -15,11 +15,7 @@ type HelpQuestionsProps = {
|
|||||||
hintText: string;
|
hintText: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const HelpQuestions = memo<HelpQuestionsProps>(function ({
|
const HelpQuestions = memo<HelpQuestionsProps>(function ({ questionId, hintVideo, hintText }) {
|
||||||
questionId,
|
|
||||||
hintVideo,
|
|
||||||
hintText,
|
|
||||||
}) {
|
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [backgroundType, setBackgroundType] = useState<BackgroundType>("text");
|
const [backgroundType, setBackgroundType] = useState<BackgroundType>("text");
|
||||||
|
|
||||||
@ -71,15 +67,17 @@ const HelpQuestions = memo<HelpQuestionsProps>(function ({
|
|||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<Box>
|
<Box>
|
||||||
<Typography sx={{ paddingBottom: "15px", fontWeight: "500" }}>
|
<Typography sx={{ paddingBottom: "15px", fontWeight: "500" }}>Загрузите видео</Typography>
|
||||||
Загрузите видео
|
|
||||||
</Typography>
|
|
||||||
<ButtonBase
|
<ButtonBase
|
||||||
onClick={() => setOpen(true)}
|
onClick={() => setOpen(true)}
|
||||||
sx={{ justifyContent: "flex-start" }}
|
sx={{ justifyContent: "flex-start" }}
|
||||||
>
|
>
|
||||||
{hintVideo ? (
|
{hintVideo ? (
|
||||||
<video src={hintVideo} width="400" controls />
|
<video
|
||||||
|
src={hintVideo}
|
||||||
|
width="400"
|
||||||
|
controls
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<UploadBox
|
<UploadBox
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
|
|
||||||
import {
|
import { getQuestionByContentId, updateQuestion } from "@root/questions/actions";
|
||||||
getQuestionByContentId,
|
|
||||||
updateQuestion,
|
|
||||||
} from "@root/questions/actions";
|
|
||||||
import { useCurrentQuiz } from "@root/quizes/hooks";
|
import { useCurrentQuiz } from "@root/quizes/hooks";
|
||||||
|
|
||||||
import CustomTextField from "@ui_kit/CustomTextField";
|
import CustomTextField from "@ui_kit/CustomTextField";
|
||||||
@ -40,11 +37,7 @@ interface Props {
|
|||||||
resultData: QuizQuestionResult;
|
resultData: QuizQuestionResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const checkEmptyData = ({
|
export const checkEmptyData = ({ resultData }: { resultData: QuizQuestionResult }) => {
|
||||||
resultData,
|
|
||||||
}: {
|
|
||||||
resultData: QuizQuestionResult;
|
|
||||||
}) => {
|
|
||||||
let check = true;
|
let check = true;
|
||||||
if (
|
if (
|
||||||
resultData.title?.length > 0 ||
|
resultData.title?.length > 0 ||
|
||||||
@ -109,15 +102,9 @@ const InfoView = ({ resultData }: { resultData: QuizQuestionResult }) => {
|
|||||||
<Typography>
|
<Typography>
|
||||||
{resultData?.content.rule.parentId === "line"
|
{resultData?.content.rule.parentId === "line"
|
||||||
? "Единый результат в конце прохождения опроса без ветвления"
|
? "Единый результат в конце прохождения опроса без ветвления"
|
||||||
: `Заголовок вопроса, после которого появится результат: "${
|
: `Заголовок вопроса, после которого появится результат: "${question?.title || "нет заголовка"}"`}
|
||||||
question?.title || "нет заголовка"
|
|
||||||
}"`}
|
|
||||||
</Typography>
|
</Typography>
|
||||||
{checkEmpty && (
|
{checkEmpty && <Typography color="red">Вы не заполнили этот результат никакими данными</Typography>}
|
||||||
<Typography color="red">
|
|
||||||
Вы не заполнили этот результат никакими данными
|
|
||||||
</Typography>
|
|
||||||
)}
|
|
||||||
</Paper>
|
</Paper>
|
||||||
</Popover>
|
</Popover>
|
||||||
</>
|
</>
|
||||||
@ -140,8 +127,7 @@ export const ResultCard = ({ resultContract, resultData }: Props) => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (
|
||||||
resultData.content.hint.text ||
|
resultData.content.hint.text ||
|
||||||
(quiz?.config.resultInfo.showResultForm === "after" &&
|
(quiz?.config.resultInfo.showResultForm === "after" && resultData.content.redirect)
|
||||||
resultData.content.redirect)
|
|
||||||
) {
|
) {
|
||||||
setButtonPlus(false);
|
setButtonPlus(false);
|
||||||
}
|
}
|
||||||
@ -167,9 +153,7 @@ export const ResultCard = ({ resultContract, resultData }: Props) => {
|
|||||||
<Typography sx={{ color: theme.palette.grey2.main, padding: "5px 20px" }}>
|
<Typography sx={{ color: theme.palette.grey2.main, padding: "5px 20px" }}>
|
||||||
{resultData?.content.rule.parentId === "line"
|
{resultData?.content.rule.parentId === "line"
|
||||||
? "Единый результат в конце прохождения опроса без ветвления"
|
? "Единый результат в конце прохождения опроса без ветвления"
|
||||||
: `Заголовок вопроса, после которого появится результат: "${
|
: `Заголовок вопроса, после которого появится результат: "${question?.title || "нет заголовка"}"`}
|
||||||
question?.title || "нет заголовка"
|
|
||||||
}"`}
|
|
||||||
</Typography>
|
</Typography>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
@ -194,16 +178,11 @@ export const ResultCard = ({ resultContract, resultData }: Props) => {
|
|||||||
placeholder={"Заголовок результата"}
|
placeholder={"Заголовок результата"}
|
||||||
maxLength={200}
|
maxLength={200}
|
||||||
onChange={({ target }: { target: HTMLInputElement }) =>
|
onChange={({ target }: { target: HTMLInputElement }) =>
|
||||||
updateQuestion(
|
updateQuestion(resultData.id, (question) => (question.title = target.value))
|
||||||
resultData.id,
|
|
||||||
(question) => (question.title = target.value),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
sx={{
|
sx={{
|
||||||
margin: isMobile ? "10px 0" : 0,
|
margin: isMobile ? "10px 0" : 0,
|
||||||
backgroundColor: expand
|
backgroundColor: expand ? theme.palette.background.default : "transparent",
|
||||||
? theme.palette.background.default
|
|
||||||
: "transparent",
|
|
||||||
height: "48px",
|
height: "48px",
|
||||||
borderRadius: "10px",
|
borderRadius: "10px",
|
||||||
borderWidth: "1px !important",
|
borderWidth: "1px !important",
|
||||||
@ -273,11 +252,7 @@ export const ResultCard = ({ resultContract, resultData }: Props) => {
|
|||||||
<Typography id={"id-copy"}>{resultData.backendId}</Typography>
|
<Typography id={"id-copy"}>{resultData.backendId}</Typography>
|
||||||
<IconButton
|
<IconButton
|
||||||
edge="end"
|
edge="end"
|
||||||
onClick={() =>
|
onClick={() => navigator.clipboard.writeText(document.querySelector("#id-copy").innerText)}
|
||||||
navigator.clipboard.writeText(
|
|
||||||
document.querySelector("#id-copy").innerText,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<CopyIcon
|
<CopyIcon
|
||||||
color={"#ffffff"}
|
color={"#ffffff"}
|
||||||
@ -300,10 +275,7 @@ export const ResultCard = ({ resultContract, resultData }: Props) => {
|
|||||||
id="headline-is-bolder"
|
id="headline-is-bolder"
|
||||||
value={resultData.description}
|
value={resultData.description}
|
||||||
onChange={({ target }: { target: HTMLInputElement }) =>
|
onChange={({ target }: { target: HTMLInputElement }) =>
|
||||||
updateQuestion(
|
updateQuestion(resultData.id, (question) => (question.description = target.value))
|
||||||
resultData.id,
|
|
||||||
(question) => (question.description = target.value),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
placeholder={"Заголовок пожирнее"}
|
placeholder={"Заголовок пожирнее"}
|
||||||
maxLength={200}
|
maxLength={200}
|
||||||
@ -335,10 +307,7 @@ export const ResultCard = ({ resultContract, resultData }: Props) => {
|
|||||||
placeholder={"Заголовок результата"}
|
placeholder={"Заголовок результата"}
|
||||||
maxLength={200}
|
maxLength={200}
|
||||||
onChange={({ target }: { target: HTMLInputElement }) =>
|
onChange={({ target }: { target: HTMLInputElement }) =>
|
||||||
updateQuestion(
|
updateQuestion(resultData.id, (question) => (question.title = target.value))
|
||||||
resultData.id,
|
|
||||||
(question) => (question.title = target.value),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
@ -350,10 +319,7 @@ export const ResultCard = ({ resultContract, resultData }: Props) => {
|
|||||||
if (target.value.length <= 3000) {
|
if (target.value.length <= 3000) {
|
||||||
setInputValue(target.value);
|
setInputValue(target.value);
|
||||||
}
|
}
|
||||||
updateQuestion(
|
updateQuestion(resultData.id, (question) => (question.content.text = target.value));
|
||||||
resultData.id,
|
|
||||||
(question) => (question.content.text = target.value),
|
|
||||||
);
|
|
||||||
}}
|
}}
|
||||||
fullWidth
|
fullWidth
|
||||||
placeholder="Описание"
|
placeholder="Описание"
|
||||||
@ -379,7 +345,7 @@ export const ResultCard = ({ resultContract, resultData }: Props) => {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<MediaSelectionAndDisplay
|
<MediaSelectionAndDisplay
|
||||||
resultData={resultData}
|
question={resultData}
|
||||||
cropAspectRatio={{ width: 305.9, height: 305.9 }}
|
cropAspectRatio={{ width: 305.9, height: 305.9 }}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -422,10 +388,7 @@ export const ResultCard = ({ resultContract, resultData }: Props) => {
|
|||||||
<IconButton
|
<IconButton
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setButtonPlus(true);
|
setButtonPlus(true);
|
||||||
updateQuestion(
|
updateQuestion(resultData.id, (q) => (q.content.hint.text = ""));
|
||||||
resultData.id,
|
|
||||||
(q) => (q.content.hint.text = ""),
|
|
||||||
);
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Trash />
|
<Trash />
|
||||||
@ -475,12 +438,9 @@ export const ResultCard = ({ resultContract, resultData }: Props) => {
|
|||||||
id="link-page-result"
|
id="link-page-result"
|
||||||
value={resultData.content.redirect}
|
value={resultData.content.redirect}
|
||||||
onChange={({ target }: { target: HTMLInputElement }) =>
|
onChange={({ target }: { target: HTMLInputElement }) =>
|
||||||
updateQuestion<QuizQuestionResult>(
|
updateQuestion<QuizQuestionResult>(resultData.id, (question) => {
|
||||||
resultData.id,
|
|
||||||
(question) => {
|
|
||||||
question.content.redirect = target.value;
|
question.content.redirect = target.value;
|
||||||
},
|
})
|
||||||
)
|
|
||||||
}
|
}
|
||||||
placeholder="https://penahub.ru"
|
placeholder="https://penahub.ru"
|
||||||
maxLength={200}
|
maxLength={200}
|
||||||
|
@ -6,16 +6,7 @@ import { useCurrentQuiz } from "@root/quizes/hooks";
|
|||||||
import { SwitchSetting } from "../SwichResult";
|
import { SwitchSetting } from "../SwichResult";
|
||||||
|
|
||||||
import Info from "@icons/Info";
|
import Info from "@icons/Info";
|
||||||
import {
|
import { Box, IconButton, Paper, Button, Typography, useMediaQuery, useTheme, Popover } from "@mui/material";
|
||||||
Box,
|
|
||||||
IconButton,
|
|
||||||
Paper,
|
|
||||||
Button,
|
|
||||||
Typography,
|
|
||||||
useMediaQuery,
|
|
||||||
useTheme,
|
|
||||||
Popover,
|
|
||||||
} from "@mui/material";
|
|
||||||
|
|
||||||
import ExpandLessIconBG from "@icons/ExpandLessIconBG";
|
import ExpandLessIconBG from "@icons/ExpandLessIconBG";
|
||||||
import ExpandLessIcon from "@mui/icons-material/ExpandLess";
|
import ExpandLessIcon from "@mui/icons-material/ExpandLess";
|
||||||
@ -88,10 +79,7 @@ const InfoView = () => {
|
|||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography>
|
<Typography>Oтправка письма с результатом респонденту после отображения на экране</Typography>
|
||||||
Oтправка письма с результатом респонденту после отображения на
|
|
||||||
экране
|
|
||||||
</Typography>
|
|
||||||
</Paper>
|
</Paper>
|
||||||
</Popover>
|
</Popover>
|
||||||
</>
|
</>
|
||||||
@ -190,7 +178,10 @@ export const WhenCard = ({ quizExpand }: Props) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{whenValues.map(({ title, value, id }, index) => (
|
{whenValues.map(({ title, value, id }, index) => (
|
||||||
<Box display="flex">
|
<Box
|
||||||
|
display="flex"
|
||||||
|
key={id}
|
||||||
|
>
|
||||||
<Button
|
<Button
|
||||||
id={id}
|
id={id}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@ -201,32 +192,16 @@ export const WhenCard = ({ quizExpand }: Props) => {
|
|||||||
}}
|
}}
|
||||||
key={title}
|
key={title}
|
||||||
sx={{
|
sx={{
|
||||||
bgcolor:
|
bgcolor: quiz?.config.resultInfo.showResultForm === value ? " #7E2AEA" : "#F2F3F7",
|
||||||
quiz?.config.resultInfo.showResultForm === value
|
color: quiz?.config.resultInfo.showResultForm === value ? " white" : "#9A9AAF",
|
||||||
? " #7E2AEA"
|
minWidth: isSmallMonitor ? (isMobile ? undefined : "310px") : "auto",
|
||||||
: "#F2F3F7",
|
|
||||||
color:
|
|
||||||
quiz?.config.resultInfo.showResultForm === value
|
|
||||||
? " white"
|
|
||||||
: "#9A9AAF",
|
|
||||||
minWidth: isSmallMonitor
|
|
||||||
? isMobile
|
|
||||||
? undefined
|
|
||||||
: "310px"
|
|
||||||
: "auto",
|
|
||||||
borderRadius: "8px",
|
borderRadius: "8px",
|
||||||
width: isMobile ? "100%" : "220px",
|
width: isMobile ? "100%" : "220px",
|
||||||
height: "44px",
|
height: "44px",
|
||||||
fontSize: "17px",
|
fontSize: "17px",
|
||||||
border:
|
border: quiz?.config.resultInfo.showResultForm === value ? "none" : "1px solid #9A9AAF",
|
||||||
quiz?.config.resultInfo.showResultForm === value
|
|
||||||
? "none"
|
|
||||||
: "1px solid #9A9AAF",
|
|
||||||
"&:hover": {
|
"&:hover": {
|
||||||
backgroundColor:
|
backgroundColor: quiz?.config.resultInfo.showResultForm === value ? "#581CA7" : "#7E2AEA",
|
||||||
quiz?.config.resultInfo.showResultForm === value
|
|
||||||
? "#581CA7"
|
|
||||||
: "#7E2AEA",
|
|
||||||
color: "white",
|
color: "white",
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
@ -252,32 +227,16 @@ export const WhenCard = ({ quizExpand }: Props) => {
|
|||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
sx={{
|
sx={{
|
||||||
bgcolor:
|
bgcolor: quiz?.config.resultInfo.when === "email" ? " #7E2AEA" : "#F2F3F7",
|
||||||
quiz?.config.resultInfo.when === "email"
|
color: quiz?.config.resultInfo.when === "email" ? " white" : "#9A9AAF",
|
||||||
? " #7E2AEA"
|
minWidth: isSmallMonitor ? (isMobile ? undefined : "310px") : "auto",
|
||||||
: "#F2F3F7",
|
|
||||||
color:
|
|
||||||
quiz?.config.resultInfo.when === "email"
|
|
||||||
? " white"
|
|
||||||
: "#9A9AAF",
|
|
||||||
minWidth: isSmallMonitor
|
|
||||||
? isMobile
|
|
||||||
? undefined
|
|
||||||
: "310px"
|
|
||||||
: "auto",
|
|
||||||
borderRadius: "8px",
|
borderRadius: "8px",
|
||||||
width: isMobile ? "100%" : "220px",
|
width: isMobile ? "100%" : "220px",
|
||||||
height: "44px",
|
height: "44px",
|
||||||
fontSize: "17px",
|
fontSize: "17px",
|
||||||
border:
|
border: quiz?.config.resultInfo.when === "email" ? "none" : "1px solid #9A9AAF",
|
||||||
quiz?.config.resultInfo.when === "email"
|
|
||||||
? "none"
|
|
||||||
: "1px solid #9A9AAF",
|
|
||||||
"&:hover": {
|
"&:hover": {
|
||||||
backgroundColor:
|
backgroundColor: quiz?.config.resultInfo.when === "email" ? "#581CA7" : "#7E2AEA",
|
||||||
quiz?.config.resultInfo.when === "email"
|
|
||||||
? "#581CA7"
|
|
||||||
: "#7E2AEA",
|
|
||||||
color: "white",
|
color: "white",
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
|
@ -27,11 +27,7 @@ import {
|
|||||||
useMediaQuery,
|
useMediaQuery,
|
||||||
useTheme,
|
useTheme,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import {
|
import { incrementCurrentStep, updateQuiz, uploadQuizImage } from "@root/quizes/actions";
|
||||||
incrementCurrentStep,
|
|
||||||
updateQuiz,
|
|
||||||
uploadQuizImage,
|
|
||||||
} from "@root/quizes/actions";
|
|
||||||
import { useCurrentQuiz } from "@root/quizes/hooks";
|
import { useCurrentQuiz } from "@root/quizes/hooks";
|
||||||
import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
||||||
import CustomTextField from "@ui_kit/CustomTextField";
|
import CustomTextField from "@ui_kit/CustomTextField";
|
||||||
@ -47,24 +43,12 @@ import { DropZone } from "./dropZone";
|
|||||||
import Extra from "./extra";
|
import Extra from "./extra";
|
||||||
import TooltipClickInfo from "@ui_kit/Toolbars/TooltipClickInfo";
|
import TooltipClickInfo from "@ui_kit/Toolbars/TooltipClickInfo";
|
||||||
import { VideoElement } from "./VideoElement";
|
import { VideoElement } from "./VideoElement";
|
||||||
import * as React from "react";
|
import UploadVideoModal from "../Questions/UploadVideoModal";
|
||||||
|
|
||||||
const designTypes = [
|
const designTypes = [
|
||||||
[
|
["standard", (color: string) => <LayoutStandartIcon color={color} />, "Standard"],
|
||||||
"standard",
|
["expanded", (color: string) => <LayoutExpandedIcon color={color} />, "Expanded"],
|
||||||
(color: string) => <LayoutStandartIcon color={color} />,
|
["centered", (color: string) => <LayoutCenteredIcon color={color} />, "Centered"],
|
||||||
"Standard",
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"expanded",
|
|
||||||
(color: string) => <LayoutExpandedIcon color={color} />,
|
|
||||||
"Expanded",
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"centered",
|
|
||||||
(color: string) => <LayoutCenteredIcon color={color} />,
|
|
||||||
"Centered",
|
|
||||||
],
|
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export default function StartPageSettings() {
|
export default function StartPageSettings() {
|
||||||
@ -78,12 +62,28 @@ export default function StartPageSettings() {
|
|||||||
const [faviconUploding, setFaviconUploading] = useState<boolean>(false);
|
const [faviconUploding, setFaviconUploading] = useState<boolean>(false);
|
||||||
const [backgroundUploding, setBackgroundUploading] = useState<boolean>(false);
|
const [backgroundUploding, setBackgroundUploading] = useState<boolean>(false);
|
||||||
const [logoUploding, setLogoUploading] = useState<boolean>(false);
|
const [logoUploding, setLogoUploading] = useState<boolean>(false);
|
||||||
|
const [isVideoUploadDialogOpen, setIsVideoUploadDialogOpen] = useState<boolean>(false);
|
||||||
|
|
||||||
if (!quiz) return null;
|
if (!quiz) return null;
|
||||||
|
|
||||||
const MobileVersionHC = (bool: boolean) => {
|
async function handleVideoUpload(videoUrl: string) {
|
||||||
setMobileVersion(bool);
|
if (!quiz) return;
|
||||||
};
|
|
||||||
|
setBackgroundUploading(true);
|
||||||
|
|
||||||
|
if (videoUrl.startsWith("blob:")) {
|
||||||
|
const videoBlob = await (await fetch(videoUrl)).blob();
|
||||||
|
uploadQuizImage(quiz.id, videoBlob, (quiz, url) => {
|
||||||
|
quiz.config.startpage.background.video = url;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
updateQuiz(quiz.id, (quiz) => {
|
||||||
|
quiz.config.startpage.background.video = videoUrl;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setBackgroundUploading(false);
|
||||||
|
}
|
||||||
|
|
||||||
const designType = quiz?.config?.startpageType;
|
const designType = quiz?.config?.startpageType;
|
||||||
let cropAspectRatio:
|
let cropAspectRatio:
|
||||||
@ -129,6 +129,12 @@ export default function StartPageSettings() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<UploadVideoModal
|
||||||
|
open={isVideoUploadDialogOpen}
|
||||||
|
onClose={() => setIsVideoUploadDialogOpen(false)}
|
||||||
|
onUpload={handleVideoUpload}
|
||||||
|
video={quiz.config.startpage.background.video}
|
||||||
|
/>
|
||||||
<Typography
|
<Typography
|
||||||
variant="h5"
|
variant="h5"
|
||||||
sx={{ marginTop: "60px", marginBottom: isSmallMonitor ? "0" : "40px" }}
|
sx={{ marginTop: "60px", marginBottom: isSmallMonitor ? "0" : "40px" }}
|
||||||
@ -143,25 +149,22 @@ export default function StartPageSettings() {
|
|||||||
fontWeight: 500,
|
fontWeight: 500,
|
||||||
fontSize: "16px",
|
fontSize: "16px",
|
||||||
color: formState === "design" ? "#7E2AEA" : "#7D7E86",
|
color: formState === "design" ? "#7E2AEA" : "#7D7E86",
|
||||||
borderBottom:
|
borderBottom: formState === "design" ? "2px solid #7E2AEA" : "1px solid transparent",
|
||||||
formState === "design"
|
|
||||||
? "2px solid #7E2AEA"
|
|
||||||
: "1px solid transparent",
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Дизайн
|
Дизайн
|
||||||
</Typography>
|
</Typography>
|
||||||
</Button>
|
</Button>
|
||||||
<Button id="contentButton" onClick={() => setFormState("content")}>
|
<Button
|
||||||
|
id="contentButton"
|
||||||
|
onClick={() => setFormState("content")}
|
||||||
|
>
|
||||||
<Typography
|
<Typography
|
||||||
sx={{
|
sx={{
|
||||||
fontWeight: 500,
|
fontWeight: 500,
|
||||||
fontSize: "16px",
|
fontSize: "16px",
|
||||||
color: formState === "content" ? "#7E2AEA" : "#7D7E86",
|
color: formState === "content" ? "#7E2AEA" : "#7D7E86",
|
||||||
borderBottom:
|
borderBottom: formState === "content" ? "2px solid #7E2AEA" : "1px solid transparent",
|
||||||
formState === "content"
|
|
||||||
? "2px solid #7E2AEA"
|
|
||||||
: "1px solid transparent",
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Контент
|
Контент
|
||||||
@ -222,8 +225,7 @@ export default function StartPageSettings() {
|
|||||||
displayEmpty
|
displayEmpty
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
updateQuiz(quiz.id, (quiz) => {
|
updateQuiz(quiz.id, (quiz) => {
|
||||||
quiz.config.startpageType = e.target
|
quiz.config.startpageType = e.target.value as QuizStartpageType;
|
||||||
.value as QuizStartpageType;
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
sx={{
|
sx={{
|
||||||
@ -280,11 +282,7 @@ export default function StartPageSettings() {
|
|||||||
color: theme.palette.grey2.main,
|
color: theme.palette.grey2.main,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{type[1](
|
{type[1](type[0] === designType ? theme.palette.orange.main : theme.palette.grey2.main)}
|
||||||
type[0] === designType
|
|
||||||
? theme.palette.orange.main
|
|
||||||
: theme.palette.grey2.main,
|
|
||||||
)}
|
|
||||||
{type[2]}
|
{type[2]}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
@ -331,10 +329,7 @@ export default function StartPageSettings() {
|
|||||||
{quiz.config.startpage.background.type === "image" && (
|
{quiz.config.startpage.background.type === "image" && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display:
|
display: quiz.config.startpage.background.type === "image" ? "flex" : "none",
|
||||||
quiz.config.startpage.background.type === "image"
|
|
||||||
? "flex"
|
|
||||||
: "none",
|
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -368,15 +363,12 @@ export default function StartPageSettings() {
|
|||||||
sx={{ maxWidth: "300px" }}
|
sx={{ maxWidth: "300px" }}
|
||||||
cropAspectRatio={cropAspectRatio}
|
cropAspectRatio={cropAspectRatio}
|
||||||
imageUrl={quiz.config.startpage.background.desktop}
|
imageUrl={quiz.config.startpage.background.desktop}
|
||||||
originalImageUrl={
|
originalImageUrl={quiz.config.startpage.background.originalDesktop}
|
||||||
quiz.config.startpage.background.originalDesktop
|
|
||||||
}
|
|
||||||
onImageUploadClick={async (file) => {
|
onImageUploadClick={async (file) => {
|
||||||
setBackgroundUploading(true);
|
setBackgroundUploading(true);
|
||||||
await uploadQuizImage(quiz.id, file, (quiz, url) => {
|
await uploadQuizImage(quiz.id, file, (quiz, url) => {
|
||||||
quiz.config.startpage.background.desktop = url;
|
quiz.config.startpage.background.desktop = url;
|
||||||
quiz.config.startpage.background.originalDesktop =
|
quiz.config.startpage.background.originalDesktop = url;
|
||||||
url;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
setBackgroundUploading(false);
|
setBackgroundUploading(false);
|
||||||
@ -426,7 +418,10 @@ export default function StartPageSettings() {
|
|||||||
{isMobile ? (
|
{isMobile ? (
|
||||||
<TooltipClickInfo title={"Можно загрузить видео."} />
|
<TooltipClickInfo title={"Можно загрузить видео."} />
|
||||||
) : (
|
) : (
|
||||||
<Tooltip title="Можно загрузить видео." placement="top">
|
<Tooltip
|
||||||
|
title="Можно загрузить видео."
|
||||||
|
placement="top"
|
||||||
|
>
|
||||||
<Box>
|
<Box>
|
||||||
<InfoIcon />
|
<InfoIcon />
|
||||||
</Box>
|
</Box>
|
||||||
@ -445,7 +440,7 @@ export default function StartPageSettings() {
|
|||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<ButtonBase
|
<ButtonBase
|
||||||
component="label"
|
onClick={() => setIsVideoUploadDialogOpen(true)}
|
||||||
sx={{
|
sx={{
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
height: "48px",
|
height: "48px",
|
||||||
@ -455,29 +450,6 @@ export default function StartPageSettings() {
|
|||||||
my: "20px",
|
my: "20px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<input
|
|
||||||
onChange={async (event) => {
|
|
||||||
setBackgroundUploading(true);
|
|
||||||
const file = event.target.files?.[0];
|
|
||||||
|
|
||||||
if (file) {
|
|
||||||
await uploadQuizImage(
|
|
||||||
quiz.id,
|
|
||||||
file,
|
|
||||||
(quiz, url) => {
|
|
||||||
quiz.config.startpage.background.video =
|
|
||||||
url;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
setBackgroundUploading(false);
|
|
||||||
}}
|
|
||||||
hidden
|
|
||||||
accept=".mp4"
|
|
||||||
multiple
|
|
||||||
type="file"
|
|
||||||
/>
|
|
||||||
<UploadBox
|
<UploadBox
|
||||||
icon={<UploadIcon />}
|
icon={<UploadIcon />}
|
||||||
sx={{
|
sx={{
|
||||||
@ -559,10 +531,7 @@ export default function StartPageSettings() {
|
|||||||
<>
|
<>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display:
|
display: quiz.config.startpage.background.type === "image" ? "flex" : "none",
|
||||||
quiz.config.startpage.background.type === "image"
|
|
||||||
? "flex"
|
|
||||||
: "none",
|
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -641,10 +610,7 @@ export default function StartPageSettings() {
|
|||||||
<>
|
<>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display:
|
display: quiz.config.startpage.background.type === "image" ? "flex" : "none",
|
||||||
quiz.config.startpage.background.type === "image"
|
|
||||||
? "flex"
|
|
||||||
: "none",
|
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -876,16 +842,18 @@ export default function StartPageSettings() {
|
|||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
updateQuiz(quiz.id, (quiz) => {
|
updateQuiz(quiz.id, (quiz) => {
|
||||||
quiz.config.antifraud = e.target.checked;
|
quiz.config.antifraud = e.target.checked;
|
||||||
|
});
|
||||||
})
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Typography sx={{fontWeight: 500,
|
<Typography
|
||||||
color: theme.palette.grey3.main,}}
|
sx={{
|
||||||
|
fontWeight: 500,
|
||||||
|
color: theme.palette.grey3.main,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
Включить антифрод</Typography>
|
Включить антифрод
|
||||||
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -2,6 +2,7 @@ import Box from "@mui/material/Box";
|
|||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
import DeleteIcon from "@mui/icons-material/Delete";
|
import DeleteIcon from "@mui/icons-material/Delete";
|
||||||
import { IconButton, SxProps, Theme } from "@mui/material";
|
import { IconButton, SxProps, Theme } from "@mui/material";
|
||||||
|
import { QuizVideo } from "@frontend/squzanswerer";
|
||||||
|
|
||||||
type VideoElementProps = {
|
type VideoElementProps = {
|
||||||
videoSrc: string;
|
videoSrc: string;
|
||||||
@ -20,12 +21,7 @@ export const VideoElement: FC<VideoElementProps> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<Box sx={{ position: "relative", width: `${width}px` }}>
|
<Box sx={{ position: "relative", width: `${width}px` }}>
|
||||||
<video
|
<QuizVideo videoUrl={videoSrc} />
|
||||||
style={{ borderRadius: "8px" }}
|
|
||||||
src={videoSrc}
|
|
||||||
width={width}
|
|
||||||
controls
|
|
||||||
/>
|
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={onDeleteClick}
|
onClick={onDeleteClick}
|
||||||
sx={{
|
sx={{
|
||||||
|
@ -20,7 +20,7 @@ export const setEditQuizId = (quizId: number | null) =>
|
|||||||
{
|
{
|
||||||
type: "setEditQuizId",
|
type: "setEditQuizId",
|
||||||
quizId,
|
quizId,
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
export const resetEditConfig = () =>
|
export const resetEditConfig = () =>
|
||||||
@ -37,7 +37,7 @@ export const setQuizes = (quizes: RawQuiz[] | null) =>
|
|||||||
{
|
{
|
||||||
type: "setQuizes",
|
type: "setQuizes",
|
||||||
quizes,
|
quizes,
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const addQuiz = (quiz: Quiz) =>
|
const addQuiz = (quiz: Quiz) =>
|
||||||
@ -48,7 +48,7 @@ const addQuiz = (quiz: Quiz) =>
|
|||||||
{
|
{
|
||||||
type: "addQuiz",
|
type: "addQuiz",
|
||||||
quiz,
|
quiz,
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const removeQuiz = (quizId: string) =>
|
const removeQuiz = (quizId: string) =>
|
||||||
@ -62,7 +62,7 @@ const removeQuiz = (quizId: string) =>
|
|||||||
{
|
{
|
||||||
type: "removeQuiz",
|
type: "removeQuiz",
|
||||||
quizId,
|
quizId,
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const setQuizBackendId = (quizId: string, backendId: number) =>
|
const setQuizBackendId = (quizId: string, backendId: number) =>
|
||||||
@ -77,20 +77,17 @@ const setQuizBackendId = (quizId: string, backendId: number) =>
|
|||||||
type: "setQuizBackendId",
|
type: "setQuizBackendId",
|
||||||
quizId,
|
quizId,
|
||||||
backendId,
|
backendId,
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
export const incrementCurrentStep = () =>
|
export const incrementCurrentStep = () =>
|
||||||
setProducedState(
|
setProducedState(
|
||||||
(state) => {
|
(state) => {
|
||||||
state.currentStep = Math.min(
|
state.currentStep = Math.min(maxQuizSetupSteps - 1, state.currentStep + 1);
|
||||||
maxQuizSetupSteps - 1,
|
|
||||||
state.currentStep + 1,
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "incrementCurrentStep",
|
type: "incrementCurrentStep",
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
export const decrementCurrentStep = () =>
|
export const decrementCurrentStep = () =>
|
||||||
@ -100,7 +97,7 @@ export const decrementCurrentStep = () =>
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "decrementCurrentStep",
|
type: "decrementCurrentStep",
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
export const setCurrentStep = (step: number) =>
|
export const setCurrentStep = (step: number) =>
|
||||||
@ -111,7 +108,7 @@ export const setCurrentStep = (step: number) =>
|
|||||||
{
|
{
|
||||||
type: "setCurrentStep",
|
type: "setCurrentStep",
|
||||||
step,
|
step,
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
export const setQuizType = (quizId: string, quizType: QuizConfig["type"]) => {
|
export const setQuizType = (quizId: string, quizType: QuizConfig["type"]) => {
|
||||||
@ -120,10 +117,7 @@ export const setQuizType = (quizId: string, quizType: QuizConfig["type"]) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const setQuizStartpageType = (
|
export const setQuizStartpageType = (quizId: string, startpageType: QuizConfig["startpageType"]) => {
|
||||||
quizId: string,
|
|
||||||
startpageType: QuizConfig["startpageType"],
|
|
||||||
) => {
|
|
||||||
updateQuiz(quizId, (quiz) => {
|
updateQuiz(quizId, (quiz) => {
|
||||||
quiz.config.startpageType = startpageType;
|
quiz.config.startpageType = startpageType;
|
||||||
});
|
});
|
||||||
@ -133,10 +127,7 @@ const REQUEST_DEBOUNCE = 200;
|
|||||||
const requestQueue = new RequestQueue();
|
const requestQueue = new RequestQueue();
|
||||||
let requestTimeoutId: ReturnType<typeof setTimeout>;
|
let requestTimeoutId: ReturnType<typeof setTimeout>;
|
||||||
|
|
||||||
export const updateQuiz = (
|
export const updateQuiz = (quizId: string | null | undefined, updateFn: (quiz: Quiz) => void) => {
|
||||||
quizId: string | null | undefined,
|
|
||||||
updateFn: (quiz: Quiz) => void,
|
|
||||||
) => {
|
|
||||||
if (!quizId) return;
|
if (!quizId) return;
|
||||||
|
|
||||||
setProducedState(
|
setProducedState(
|
||||||
@ -150,7 +141,7 @@ export const updateQuiz = (
|
|||||||
type: "updateQuiz",
|
type: "updateQuiz",
|
||||||
quizId,
|
quizId,
|
||||||
updateFn: updateFn.toString(),
|
updateFn: updateFn.toString(),
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
clearTimeout(requestTimeoutId);
|
clearTimeout(requestTimeoutId);
|
||||||
@ -159,9 +150,7 @@ export const updateQuiz = (
|
|||||||
const quiz = useQuizStore.getState().quizes.find((q) => q.id === quizId);
|
const quiz = useQuizStore.getState().quizes.find((q) => q.id === quizId);
|
||||||
if (!quiz) return;
|
if (!quiz) return;
|
||||||
|
|
||||||
const [editedQuiz, editedQuizError] = await quizApi.edit(
|
const [editedQuiz, editedQuizError] = await quizApi.edit(quizToEditQuizRequest(quiz));
|
||||||
quizToEditQuizRequest(quiz),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (editedQuizError || !editedQuiz) {
|
if (editedQuizError || !editedQuiz) {
|
||||||
devlog("Error editing quiz", editedQuizError, quizId);
|
devlog("Error editing quiz", editedQuizError, quizId);
|
||||||
@ -270,22 +259,15 @@ export const copyQuiz = async (quizId: string) =>
|
|||||||
(state) => {
|
(state) => {
|
||||||
state.quizes.unshift(newQuiz);
|
state.quizes.unshift(newQuiz);
|
||||||
},
|
},
|
||||||
{ type: "addQuiz", quiz },
|
{ type: "addQuiz", quiz }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
export const uploadQuizImage = async (
|
export const uploadQuizImage = async (quizId: string, blob: Blob, updateFn: (quiz: Quiz, imageId: string) => void) => {
|
||||||
quizId: string,
|
|
||||||
blob: Blob,
|
|
||||||
updateFn: (quiz: Quiz, imageId: string) => void,
|
|
||||||
) => {
|
|
||||||
const quiz = useQuizStore.getState().quizes.find((q) => q.id === quizId);
|
const quiz = useQuizStore.getState().quizes.find((q) => q.id === quizId);
|
||||||
if (!quiz) return;
|
if (!quiz) return;
|
||||||
|
|
||||||
const [addedImages, addImagesError] = await quizApi.addImages(
|
const [addedImages, addImagesError] = await quizApi.addImages(quiz.backendId, blob);
|
||||||
quiz.backendId,
|
|
||||||
blob,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (addImagesError || !addedImages) {
|
if (addImagesError || !addedImages) {
|
||||||
devlog("Error uploading quiz image", addImagesError);
|
devlog("Error uploading quiz image", addImagesError);
|
||||||
@ -305,14 +287,11 @@ export const uploadQuizImage = async (
|
|||||||
updateQuiz(quizId, (quiz) => {
|
updateQuiz(quizId, (quiz) => {
|
||||||
updateFn(
|
updateFn(
|
||||||
quiz,
|
quiz,
|
||||||
`https://s3.timeweb.cloud/3c580be9-cf31f296-d055-49cf-b39e-30c7959dc17b/squizimages/${quiz.qid}/${imageId}`,
|
`https://s3.timeweb.cloud/3c580be9-cf31f296-d055-49cf-b39e-30c7959dc17b/squizimages/${quiz.qid}/${imageId}`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function setProducedState<A extends string | { type: unknown }>(
|
function setProducedState<A extends string | { type: string }>(recipe: (state: QuizStore) => void, action?: A) {
|
||||||
recipe: (state: QuizStore) => void,
|
|
||||||
action?: A,
|
|
||||||
) {
|
|
||||||
useQuizStore.setState((state) => produce(state, recipe), false, action);
|
useQuizStore.setState((state) => produce(state, recipe), false, action);
|
||||||
}
|
}
|
||||||
|
@ -6,19 +6,13 @@ import type { SxProps, Theme } from "@mui/material";
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
sx?: SxProps<Theme>;
|
sx?: SxProps<Theme>;
|
||||||
imageSrc?: string;
|
imageSrc?: string | null;
|
||||||
onImageClick?: () => void;
|
onImageClick?: () => void;
|
||||||
onPlusClick?: () => void;
|
onPlusClick?: () => void;
|
||||||
uploading: boolean;
|
uploading: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function AddOrEditImageButton({
|
export default function AddOrEditImageButton({ onImageClick, onPlusClick, sx, imageSrc, uploading = false }: Props) {
|
||||||
onImageClick,
|
|
||||||
onPlusClick,
|
|
||||||
sx,
|
|
||||||
imageSrc,
|
|
||||||
uploading = false,
|
|
||||||
}: Props) {
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
||||||
|
|
||||||
|
@ -1,64 +1,44 @@
|
|||||||
import { FC, useState } from "react";
|
import { QuizQuestionPage } from "@/model/questionTypes/page";
|
||||||
import {
|
import { QuizQuestionResult } from "@/model/questionTypes/result";
|
||||||
Box,
|
|
||||||
Button,
|
|
||||||
ButtonBase,
|
|
||||||
Skeleton,
|
|
||||||
Tooltip,
|
|
||||||
Typography,
|
|
||||||
useTheme,
|
|
||||||
} from "@mui/material";
|
|
||||||
import { updateQuestion, uploadQuestionImage } from "@root/questions/actions";
|
|
||||||
import { CropModal, useCropModalState } from "@ui_kit/Modal/CropModal";
|
|
||||||
|
|
||||||
import AddOrEditImageButton from "@ui_kit/AddOrEditImageButton";
|
|
||||||
import { UploadImageModal } from "../pages/Questions/UploadImage/UploadImageModal";
|
|
||||||
import { useDisclosure } from "../utils/useDisclosure";
|
|
||||||
import { useCurrentQuiz } from "../stores/quizes/hooks";
|
|
||||||
import { AnyTypedQuizQuestion } from "@model/questionTypes/shared";
|
|
||||||
import UploadBox from "@ui_kit/UploadBox";
|
|
||||||
import UploadIcon from "@icons/UploadIcon";
|
|
||||||
import InfoIcon from "@icons/InfoIcon";
|
import InfoIcon from "@icons/InfoIcon";
|
||||||
|
import UploadIcon from "@icons/UploadIcon";
|
||||||
|
import { Box, Button, ButtonBase, Skeleton, Tooltip, Typography, useTheme } from "@mui/material";
|
||||||
|
import { updateQuestion, uploadQuestionImage } from "@root/questions/actions";
|
||||||
|
import AddOrEditImageButton from "@ui_kit/AddOrEditImageButton";
|
||||||
|
import { CropModal, useCropModalState } from "@ui_kit/Modal/CropModal";
|
||||||
|
import UploadBox from "@ui_kit/UploadBox";
|
||||||
|
import { FC, useState } from "react";
|
||||||
|
import { UploadImageModal } from "../pages/Questions/UploadImage/UploadImageModal";
|
||||||
import { VideoElement } from "../pages/startPage/VideoElement";
|
import { VideoElement } from "../pages/startPage/VideoElement";
|
||||||
|
import { useCurrentQuiz } from "../stores/quizes/hooks";
|
||||||
|
import { useDisclosure } from "../utils/useDisclosure";
|
||||||
|
import UploadVideoModal from "@/pages/Questions/UploadVideoModal";
|
||||||
|
|
||||||
interface Iprops {
|
interface Props {
|
||||||
resultData: AnyTypedQuizQuestion;
|
question: QuizQuestionPage | QuizQuestionResult;
|
||||||
cropAspectRatio: {
|
cropAspectRatio: {
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MediaSelectionAndDisplay: FC<Iprops> = ({
|
export const MediaSelectionAndDisplay: FC<Props> = ({ question, cropAspectRatio }) => {
|
||||||
resultData,
|
|
||||||
cropAspectRatio,
|
|
||||||
}) => {
|
|
||||||
const [pictureUploding, setPictureUploading] = useState<boolean>(false);
|
const [pictureUploding, setPictureUploading] = useState<boolean>(false);
|
||||||
const [backgroundUploding, setBackgroundUploading] = useState<boolean>(false);
|
const [backgroundUploding, setBackgroundUploading] = useState<boolean>(false);
|
||||||
const quizQid = useCurrentQuiz()?.qid;
|
const quizQid = useCurrentQuiz()?.qid;
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const {
|
const { isCropModalOpen, openCropModal, closeCropModal, imageBlob, originalImageUrl, setCropModalImageBlob } =
|
||||||
isCropModalOpen,
|
useCropModalState();
|
||||||
openCropModal,
|
const [isImageUploadOpen, openImageUploadModal, closeImageUploadModal] = useDisclosure();
|
||||||
closeCropModal,
|
const [isVideoUploadDialogOpen, setIsVideoUploadDialogOpen] = useState<boolean>(false);
|
||||||
imageBlob,
|
|
||||||
originalImageUrl,
|
|
||||||
setCropModalImageBlob,
|
|
||||||
} = useCropModalState();
|
|
||||||
const [isImageUploadOpen, openImageUploadModal, closeImageUploadModal] =
|
|
||||||
useDisclosure();
|
|
||||||
async function handleImageUpload(file: File) {
|
async function handleImageUpload(file: File) {
|
||||||
setPictureUploading(true);
|
setPictureUploading(true);
|
||||||
|
|
||||||
const url = await uploadQuestionImage(
|
const url = await uploadQuestionImage(question.id, quizQid, file, (question, url) => {
|
||||||
resultData.id,
|
|
||||||
quizQid,
|
|
||||||
file,
|
|
||||||
(question, url) => {
|
|
||||||
question.content.back = url;
|
question.content.back = url;
|
||||||
question.content.originalBack = url;
|
question.content.originalBack = url;
|
||||||
},
|
});
|
||||||
);
|
|
||||||
closeImageUploadModal();
|
closeImageUploadModal();
|
||||||
openCropModal(file, url);
|
openCropModal(file, url);
|
||||||
|
|
||||||
@ -66,11 +46,32 @@ export const MediaSelectionAndDisplay: FC<Iprops> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleCropModalSaveClick(imageBlob: Blob) {
|
function handleCropModalSaveClick(imageBlob: Blob) {
|
||||||
uploadQuestionImage(resultData.id, quizQid, imageBlob, (question, url) => {
|
uploadQuestionImage(question.id, quizQid, imageBlob, (question, url) => {
|
||||||
question.content.back = url;
|
question.content.back = url;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function handleVideoUpload(videoUrl: string) {
|
||||||
|
setBackgroundUploading(true);
|
||||||
|
|
||||||
|
if (videoUrl.startsWith("blob:")) {
|
||||||
|
const videoBlob = await (await fetch(videoUrl)).blob();
|
||||||
|
uploadQuestionImage(question.id, quizQid, videoBlob, (question, url) => {
|
||||||
|
if (!("video" in question.content)) return;
|
||||||
|
|
||||||
|
question.content.video = url;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
updateQuestion(question.id, (question) => {
|
||||||
|
if (!("video" in question.content)) return;
|
||||||
|
|
||||||
|
question.content.video = videoUrl;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setBackgroundUploading(false);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
@ -87,7 +88,7 @@ export const MediaSelectionAndDisplay: FC<Iprops> = ({
|
|||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
sx={{
|
sx={{
|
||||||
color: resultData.content.useImage ? "#7E2AEA" : "#9A9AAF",
|
color: question.content.useImage ? "#7E2AEA" : "#9A9AAF",
|
||||||
fontSize: "16px",
|
fontSize: "16px",
|
||||||
"&:hover": {
|
"&:hover": {
|
||||||
background: "none",
|
background: "none",
|
||||||
@ -95,17 +96,18 @@ export const MediaSelectionAndDisplay: FC<Iprops> = ({
|
|||||||
}}
|
}}
|
||||||
variant="text"
|
variant="text"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
updateQuestion(
|
updateQuestion(question.id, (question) => {
|
||||||
resultData.id,
|
if (!("useImage" in question.content)) return;
|
||||||
(question) => (question.content.useImage = true),
|
|
||||||
)
|
question.content.useImage = true;
|
||||||
|
})
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
Изображение
|
Изображение
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
sx={{
|
sx={{
|
||||||
color: resultData.content.useImage ? "#9A9AAF" : "#7E2AEA",
|
color: question.content.useImage ? "#9A9AAF" : "#7E2AEA",
|
||||||
fontSize: "16px",
|
fontSize: "16px",
|
||||||
"&:hover": {
|
"&:hover": {
|
||||||
background: "none",
|
background: "none",
|
||||||
@ -113,22 +115,16 @@ export const MediaSelectionAndDisplay: FC<Iprops> = ({
|
|||||||
}}
|
}}
|
||||||
variant="text"
|
variant="text"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
updateQuestion(
|
updateQuestion(question.id, (question) => {
|
||||||
resultData.id,
|
if (!("useImage" in question.content)) return;
|
||||||
(question) => (question.content.useImage = false),
|
|
||||||
)
|
question.content.useImage = false;
|
||||||
|
})
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
Видео
|
Видео
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<UploadImageModal
|
<UploadImageModal
|
||||||
isOpen={isImageUploadOpen}
|
isOpen={isImageUploadOpen}
|
||||||
onClose={closeImageUploadModal}
|
onClose={closeImageUploadModal}
|
||||||
@ -142,16 +138,20 @@ export const MediaSelectionAndDisplay: FC<Iprops> = ({
|
|||||||
onClose={closeCropModal}
|
onClose={closeCropModal}
|
||||||
onSaveImageClick={handleCropModalSaveClick}
|
onSaveImageClick={handleCropModalSaveClick}
|
||||||
onDeleteClick={() => {
|
onDeleteClick={() => {
|
||||||
updateQuestion(resultData.id, (question) => {
|
updateQuestion(question.id, (question) => {
|
||||||
question.content.back = null;
|
question.content.back = null;
|
||||||
question.content.originalBack = null;
|
question.content.originalBack = null;
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
cropAspectRatio={cropAspectRatio}
|
cropAspectRatio={cropAspectRatio}
|
||||||
/>
|
/>
|
||||||
</Box>
|
<UploadVideoModal
|
||||||
|
open={isVideoUploadDialogOpen}
|
||||||
{resultData.content.useImage && (
|
onClose={() => setIsVideoUploadDialogOpen(false)}
|
||||||
|
onUpload={handleVideoUpload}
|
||||||
|
video={question.content.video}
|
||||||
|
/>
|
||||||
|
{question.content.useImage && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
@ -162,14 +162,11 @@ export const MediaSelectionAndDisplay: FC<Iprops> = ({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<AddOrEditImageButton
|
<AddOrEditImageButton
|
||||||
imageSrc={resultData.content.back}
|
imageSrc={question.content.back}
|
||||||
uploading={pictureUploding}
|
uploading={pictureUploding}
|
||||||
onImageClick={() => {
|
onImageClick={() => {
|
||||||
if (resultData.content.back) {
|
if (question.content.back) {
|
||||||
return openCropModal(
|
return openCropModal(question.content.back, question.content.originalBack);
|
||||||
resultData.content.back,
|
|
||||||
resultData.content.originalBack,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
openImageUploadModal();
|
openImageUploadModal();
|
||||||
@ -180,9 +177,9 @@ export const MediaSelectionAndDisplay: FC<Iprops> = ({
|
|||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
{!resultData.content.useImage && (
|
{!question.content.useImage && (
|
||||||
<>
|
<>
|
||||||
{!resultData.content.video ? (
|
{!question.content.video ? (
|
||||||
<>
|
<>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
@ -193,12 +190,11 @@ export const MediaSelectionAndDisplay: FC<Iprops> = ({
|
|||||||
mb: "14px",
|
mb: "14px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography
|
<Typography sx={{ fontWeight: 500, color: theme.palette.grey3.main }}>Добавить видео</Typography>
|
||||||
sx={{ fontWeight: 500, color: theme.palette.grey3.main }}
|
<Tooltip
|
||||||
|
title="Можно загрузить видео."
|
||||||
|
placement="top"
|
||||||
>
|
>
|
||||||
Добавить видео
|
|
||||||
</Typography>
|
|
||||||
<Tooltip title="Можно загрузить видео." placement="top">
|
|
||||||
<Box>
|
<Box>
|
||||||
<InfoIcon />
|
<InfoIcon />
|
||||||
</Box>
|
</Box>
|
||||||
@ -216,7 +212,7 @@ export const MediaSelectionAndDisplay: FC<Iprops> = ({
|
|||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<ButtonBase
|
<ButtonBase
|
||||||
component="label"
|
onClick={() => setIsVideoUploadDialogOpen(true)}
|
||||||
sx={{
|
sx={{
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
height: "48px",
|
height: "48px",
|
||||||
@ -226,27 +222,6 @@ export const MediaSelectionAndDisplay: FC<Iprops> = ({
|
|||||||
my: "20px",
|
my: "20px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<input
|
|
||||||
onChange={async (event) => {
|
|
||||||
setBackgroundUploading(true);
|
|
||||||
const file = event.target.files?.[0];
|
|
||||||
if (file) {
|
|
||||||
await uploadQuestionImage(
|
|
||||||
resultData.id,
|
|
||||||
quizQid,
|
|
||||||
file,
|
|
||||||
(question, url) => {
|
|
||||||
question.content.video = url;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
setBackgroundUploading(false);
|
|
||||||
}}
|
|
||||||
hidden
|
|
||||||
accept=".mp4"
|
|
||||||
multiple
|
|
||||||
type="file"
|
|
||||||
/>
|
|
||||||
<UploadBox
|
<UploadBox
|
||||||
icon={<UploadIcon />}
|
icon={<UploadIcon />}
|
||||||
sx={{
|
sx={{
|
||||||
@ -260,10 +235,12 @@ export const MediaSelectionAndDisplay: FC<Iprops> = ({
|
|||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<VideoElement
|
<VideoElement
|
||||||
videoSrc={resultData.content.video}
|
videoSrc={question.content.video}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
onDeleteClick={() => {
|
onDeleteClick={() => {
|
||||||
updateQuestion(resultData.id, (question) => {
|
updateQuestion(question.id, (question) => {
|
||||||
|
if (!("video" in question.content)) return;
|
||||||
|
|
||||||
question.content.video = null;
|
question.content.video = null;
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
39
yarn.lock
39
yarn.lock
@ -1521,10 +1521,10 @@
|
|||||||
immer "^10.0.2"
|
immer "^10.0.2"
|
||||||
reconnecting-eventsource "^1.6.2"
|
reconnecting-eventsource "^1.6.2"
|
||||||
|
|
||||||
"@frontend/squzanswerer@^1.0.44":
|
"@frontend/squzanswerer@^1.0.45":
|
||||||
version "1.0.44"
|
version "1.0.45"
|
||||||
resolved "https://penahub.gitlab.yandexcloud.net/api/v4/projects/43/packages/npm/@frontend/squzanswerer/-/@frontend/squzanswerer-1.0.44.tgz#12c19b23a1e1eff4d0cbfeffbc9ed1160c49cde2"
|
resolved "https://penahub.gitlab.yandexcloud.net/api/v4/projects/43/packages/npm/@frontend/squzanswerer/-/@frontend/squzanswerer-1.0.45.tgz#1124aaa099034b0b75eda7b5c91f457db47872ab"
|
||||||
integrity sha1-EsGbI6Hh7/TQy/7/vJ7RFgxJzeI=
|
integrity sha1-ESSqoJkDSwt17ae1yR9FfbR4cqs=
|
||||||
dependencies:
|
dependencies:
|
||||||
bowser "1.9.4"
|
bowser "1.9.4"
|
||||||
country-flag-emoji-polyfill "^0.1.8"
|
country-flag-emoji-polyfill "^0.1.8"
|
||||||
@ -10557,16 +10557,7 @@ string-natural-compare@^3.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4"
|
resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4"
|
||||||
integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==
|
integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==
|
||||||
|
|
||||||
"string-width-cjs@npm:string-width@^4.2.0":
|
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0:
|
||||||
version "4.2.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
|
||||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
|
||||||
dependencies:
|
|
||||||
emoji-regex "^8.0.0"
|
|
||||||
is-fullwidth-code-point "^3.0.0"
|
|
||||||
strip-ansi "^6.0.1"
|
|
||||||
|
|
||||||
string-width@^4.1.0, string-width@^4.2.0:
|
|
||||||
version "4.2.3"
|
version "4.2.3"
|
||||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||||
@ -10662,14 +10653,7 @@ stringify-object@^3.3.0:
|
|||||||
is-obj "^1.0.1"
|
is-obj "^1.0.1"
|
||||||
is-regexp "^1.0.0"
|
is-regexp "^1.0.0"
|
||||||
|
|
||||||
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
|
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
||||||
version "6.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
|
||||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
|
||||||
dependencies:
|
|
||||||
ansi-regex "^5.0.1"
|
|
||||||
|
|
||||||
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
|
||||||
version "6.0.1"
|
version "6.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||||
@ -11856,7 +11840,7 @@ workbox-window@6.6.1:
|
|||||||
"@types/trusted-types" "^2.0.2"
|
"@types/trusted-types" "^2.0.2"
|
||||||
workbox-core "6.6.1"
|
workbox-core "6.6.1"
|
||||||
|
|
||||||
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
|
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
|
||||||
version "7.0.0"
|
version "7.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
||||||
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
||||||
@ -11874,15 +11858,6 @@ wrap-ansi@^6.2.0:
|
|||||||
string-width "^4.1.0"
|
string-width "^4.1.0"
|
||||||
strip-ansi "^6.0.0"
|
strip-ansi "^6.0.0"
|
||||||
|
|
||||||
wrap-ansi@^7.0.0:
|
|
||||||
version "7.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
|
||||||
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
|
||||||
dependencies:
|
|
||||||
ansi-styles "^4.0.0"
|
|
||||||
string-width "^4.1.0"
|
|
||||||
strip-ansi "^6.0.0"
|
|
||||||
|
|
||||||
wrap-ansi@^8.1.0:
|
wrap-ansi@^8.1.0:
|
||||||
version "8.1.0"
|
version "8.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
|
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
|
||||||
|
Loading…
Reference in New Issue
Block a user