diff --git a/package.json b/package.json
index 50ce7a0f..ca44eab3 100755
--- a/package.json
+++ b/package.json
@@ -7,7 +7,7 @@
"@emotion/react": "^11.10.5",
"@emotion/styled": "^11.10.5",
"@frontend/kitui": "^1.0.82",
- "@frontend/squzanswerer": "^1.0.44",
+ "@frontend/squzanswerer": "^1.0.45",
"@mui/icons-material": "^5.10.14",
"@mui/material": "^5.10.14",
"@mui/x-charts": "^6.19.5",
diff --git a/src/model/questionTypes/page.ts b/src/model/questionTypes/page.ts
index ba6eb261..7c7ee461 100644
--- a/src/model/questionTypes/page.ts
+++ b/src/model/questionTypes/page.ts
@@ -12,7 +12,7 @@ export interface QuizQuestionPage extends QuizQuestionBase {
picture: string;
originalPicture: string;
useImage: boolean;
- video: string;
+ video: string | null;
hint: QuestionHint;
rule: PreviewRule;
back: string;
diff --git a/src/model/questionTypes/result.ts b/src/model/questionTypes/result.ts
index 5b084765..16564007 100644
--- a/src/model/questionTypes/result.ts
+++ b/src/model/questionTypes/result.ts
@@ -1,8 +1,4 @@
-import type {
- QuizQuestionBase,
- QuestionBranchingRule,
- QuestionHint,
-} from "./shared";
+import type { QuizQuestionBase, QuestionBranchingRule, QuestionHint } from "./shared";
export interface QuizQuestionResult extends QuizQuestionBase {
type: "result";
@@ -10,7 +6,7 @@ export interface QuizQuestionResult extends QuizQuestionBase {
id: string;
back: string;
originalBack: string;
- video: string;
+ video: string | null;
innerName: string;
text: string;
price: [number] | [number, number];
diff --git a/src/pages/Questions/PageOptions/PageOptions.tsx b/src/pages/Questions/PageOptions/PageOptions.tsx
index ac9b4b48..d1811a09 100644
--- a/src/pages/Questions/PageOptions/PageOptions.tsx
+++ b/src/pages/Questions/PageOptions/PageOptions.tsx
@@ -1,18 +1,5 @@
-import {
- Box,
- Button,
- IconButton,
- Modal,
- Typography,
- useMediaQuery,
- useTheme,
-} from "@mui/material";
-import {
- copyQuestion,
- deleteQuestion,
- deleteQuestionWithTimeout,
- updateQuestion,
-} from "@root/questions/actions";
+import { Box, 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 { CopyIcon } from "@icons/questionsPage/CopyIcon";
@@ -71,7 +58,7 @@ export default function PageOptions({ disableInput, question }: Props) {
@@ -107,16 +94,17 @@ export default function PageOptions({ disableInput, question }: Props) {
if (question.content.rule.parentId.length !== 0) {
setOpenDelete(true);
} else {
- deleteQuestionWithTimeout(question.id, () =>
- DeleteFunction(question.id),
- );
+ deleteQuestionWithTimeout(question.id, () => DeleteFunction(question.id));
}
}}
data-cy="delete-question"
>
- setOpenDelete(false)}>
+ setOpenDelete(false)}
+ >
-
- Вы удаляете вопрос, участвующий в ветвлении. Все его потомки
- потеряют данные ветвления. Вы уверены, что хотите удалить
- вопрос?
+
+ Вы удаляете вопрос, участвующий в ветвлении. Все его потомки потеряют данные ветвления. Вы уверены, что
+ хотите удалить вопрос?
{
- deleteQuestionWithTimeout(question.id, () =>
- DeleteFunction(question.id),
- );
+ deleteQuestionWithTimeout(question.id, () => DeleteFunction(question.id));
}}
>
Подтвердить
diff --git a/src/pages/Questions/UploadVideoModal.tsx b/src/pages/Questions/UploadVideoModal.tsx
index 0adb6d0a..374c86f2 100644
--- a/src/pages/Questions/UploadVideoModal.tsx
+++ b/src/pages/Questions/UploadVideoModal.tsx
@@ -1,16 +1,8 @@
-import {
- Box,
- Button,
- ButtonBase,
- Modal,
- Typography,
- useTheme,
-} from "@mui/material";
-import SelectableButton from "@ui_kit/SelectableButton";
+import { Box, Button, ButtonBase, Dialog, Typography, useTheme } from "@mui/material";
import CustomTextField from "@ui_kit/CustomTextField";
+import SelectableButton from "@ui_kit/SelectableButton";
import { useState } from "react";
import UploadIcon from "../../assets/icons/UploadIcon";
-
import type { DragEvent } from "react";
type BackgroundTypeModal = "linkVideo" | "ownVideo";
@@ -18,18 +10,12 @@ type BackgroundTypeModal = "linkVideo" | "ownVideo";
type HelpQuestionsProps = {
open: boolean;
onClose: () => void;
- video: string;
+ video: string | null;
onUpload: (number: string) => void;
};
-export const UploadVideoModal = ({
- open,
- onClose,
- video,
- onUpload,
-}: HelpQuestionsProps) => {
- const [backgroundTypeModal, setBackgroundTypeModal] =
- useState("linkVideo");
+export default function UploadVideoModal({ open, onClose, video, onUpload }: HelpQuestionsProps) {
+ const [backgroundTypeModal, setBackgroundTypeModal] = useState("linkVideo");
const theme = useTheme();
const handleDrop = (event: DragEvent) => {
@@ -42,118 +28,102 @@ export const UploadVideoModal = ({
};
return (
-
-
+
-
+ Видео можно вставить с любого хостинга: YouTube, Vimeo или загрузить собственное
+
+
-
- setBackgroundTypeModal("linkVideo")}
- sx={{ maxWidth: "170px", padding: "10px" }}
- >
- Ссылка на видео
-
- setBackgroundTypeModal("ownVideo")}
- sx={{ maxWidth: "170px", padding: "10px" }}
- >
- Загрузить свое
-
-
- {backgroundTypeModal === "linkVideo" ? (
-
-
- Ссылка на видео
-
- onUpload(target.value || " ")}
- />
-
- ) : (
-
-
- Загрузите видео
-
-
- {
- if (target.files?.length) {
- onUpload(URL.createObjectURL(target.files[0] || " "));
- }
- }}
- hidden
- accept="video/*"
- multiple
- type="file"
- />
- ) =>
- event.preventDefault()
- }
- onDrop={handleDrop}
- sx={{
- width: "580px",
- padding: "33px 33px 33px 50px",
- display: "flex",
- alignItems: "center",
- backgroundColor: theme.palette.background.default,
- border: `1px solid ${theme.palette.grey2.main}`,
- borderRadius: "8px",
- gap: "50px",
- }}
- >
-
-
-
- Добавить видео
-
-
- Принимает .mp4 и .mov формат — максимум 100мб
-
-
-
-
-
- )}
+ Готово
+
-
+
+ setBackgroundTypeModal("linkVideo")}
+ sx={{ maxWidth: "170px", padding: "10px" }}
+ >
+ Ссылка на видео
+
+ setBackgroundTypeModal("ownVideo")}
+ sx={{ maxWidth: "170px", padding: "10px" }}
+ >
+ Загрузить свое
+
+
+ {backgroundTypeModal === "linkVideo" ? (
+
+ Ссылка на видео
+ onUpload(target.value || " ")}
+ />
+
+ ) : (
+
+ Загрузите видео
+
+ {
+ if (target.files?.length) {
+ onUpload(URL.createObjectURL(target.files[0] || " "));
+ }
+ }}
+ hidden
+ accept="video/*"
+ multiple
+ type="file"
+ />
+ ) => event.preventDefault()}
+ onDrop={handleDrop}
+ sx={{
+ width: "580px",
+ padding: "33px 33px 33px 50px",
+ display: "flex",
+ alignItems: "center",
+ backgroundColor: theme.palette.background.default,
+ border: `1px solid ${theme.palette.grey2.main}`,
+ borderRadius: "8px",
+ gap: "50px",
+ }}
+ >
+
+
+ Добавить видео
+ Принимает .mp4 и .mov формат — максимум 100мб
+
+
+
+
+ )}
+
);
-};
+}
diff --git a/src/pages/Questions/helpQuestions.tsx b/src/pages/Questions/helpQuestions.tsx
index ede9b174..c811bccf 100644
--- a/src/pages/Questions/helpQuestions.tsx
+++ b/src/pages/Questions/helpQuestions.tsx
@@ -5,7 +5,7 @@ import SelectableButton from "@ui_kit/SelectableButton";
import UploadBox from "@ui_kit/UploadBox";
import { memo, useState } from "react";
import UploadIcon from "../../assets/icons/UploadIcon";
-import { UploadVideoModal } from "./UploadVideoModal";
+import UploadVideoModal from "./UploadVideoModal";
type BackgroundType = "text" | "video";
@@ -15,11 +15,7 @@ type HelpQuestionsProps = {
hintText: string;
};
-const HelpQuestions = memo(function ({
- questionId,
- hintVideo,
- hintText,
-}) {
+const HelpQuestions = memo(function ({ questionId, hintVideo, hintText }) {
const [open, setOpen] = useState(false);
const [backgroundType, setBackgroundType] = useState("text");
@@ -71,15 +67,17 @@ const HelpQuestions = memo(function ({
>
) : (
-
- Загрузите видео
-
+ Загрузите видео
setOpen(true)}
sx={{ justifyContent: "flex-start" }}
>
{hintVideo ? (
-
+
) : (
<>
{
+export const checkEmptyData = ({ resultData }: { resultData: QuizQuestionResult }) => {
let check = true;
if (
resultData.title?.length > 0 ||
@@ -109,15 +102,9 @@ const InfoView = ({ resultData }: { resultData: QuizQuestionResult }) => {
{resultData?.content.rule.parentId === "line"
? "Единый результат в конце прохождения опроса без ветвления"
- : `Заголовок вопроса, после которого появится результат: "${
- question?.title || "нет заголовка"
- }"`}
+ : `Заголовок вопроса, после которого появится результат: "${question?.title || "нет заголовка"}"`}
- {checkEmpty && (
-
- Вы не заполнили этот результат никакими данными
-
- )}
+ {checkEmpty && Вы не заполнили этот результат никакими данными}
>
@@ -140,8 +127,7 @@ export const ResultCard = ({ resultContract, resultData }: Props) => {
useEffect(() => {
if (
resultData.content.hint.text ||
- (quiz?.config.resultInfo.showResultForm === "after" &&
- resultData.content.redirect)
+ (quiz?.config.resultInfo.showResultForm === "after" && resultData.content.redirect)
) {
setButtonPlus(false);
}
@@ -167,9 +153,7 @@ export const ResultCard = ({ resultContract, resultData }: Props) => {
{resultData?.content.rule.parentId === "line"
? "Единый результат в конце прохождения опроса без ветвления"
- : `Заголовок вопроса, после которого появится результат: "${
- question?.title || "нет заголовка"
- }"`}
+ : `Заголовок вопроса, после которого появится результат: "${question?.title || "нет заголовка"}"`}
{
placeholder={"Заголовок результата"}
maxLength={200}
onChange={({ target }: { target: HTMLInputElement }) =>
- updateQuestion(
- resultData.id,
- (question) => (question.title = target.value),
- )
+ updateQuestion(resultData.id, (question) => (question.title = target.value))
}
sx={{
margin: isMobile ? "10px 0" : 0,
- backgroundColor: expand
- ? theme.palette.background.default
- : "transparent",
+ backgroundColor: expand ? theme.palette.background.default : "transparent",
height: "48px",
borderRadius: "10px",
borderWidth: "1px !important",
@@ -273,11 +252,7 @@ export const ResultCard = ({ resultContract, resultData }: Props) => {
{resultData.backendId}
- navigator.clipboard.writeText(
- document.querySelector("#id-copy").innerText,
- )
- }
+ onClick={() => navigator.clipboard.writeText(document.querySelector("#id-copy").innerText)}
>
{
id="headline-is-bolder"
value={resultData.description}
onChange={({ target }: { target: HTMLInputElement }) =>
- updateQuestion(
- resultData.id,
- (question) => (question.description = target.value),
- )
+ updateQuestion(resultData.id, (question) => (question.description = target.value))
}
placeholder={"Заголовок пожирнее"}
maxLength={200}
@@ -335,10 +307,7 @@ export const ResultCard = ({ resultContract, resultData }: Props) => {
placeholder={"Заголовок результата"}
maxLength={200}
onChange={({ target }: { target: HTMLInputElement }) =>
- updateQuestion(
- resultData.id,
- (question) => (question.title = target.value),
- )
+ updateQuestion(resultData.id, (question) => (question.title = target.value))
}
/>
@@ -350,10 +319,7 @@ export const ResultCard = ({ resultContract, resultData }: Props) => {
if (target.value.length <= 3000) {
setInputValue(target.value);
}
- updateQuestion(
- resultData.id,
- (question) => (question.content.text = target.value),
- );
+ updateQuestion(resultData.id, (question) => (question.content.text = target.value));
}}
fullWidth
placeholder="Описание"
@@ -379,7 +345,7 @@ export const ResultCard = ({ resultContract, resultData }: Props) => {
/>
@@ -422,10 +388,7 @@ export const ResultCard = ({ resultContract, resultData }: Props) => {
{
setButtonPlus(true);
- updateQuestion(
- resultData.id,
- (q) => (q.content.hint.text = ""),
- );
+ updateQuestion(resultData.id, (q) => (q.content.hint.text = ""));
}}
>
@@ -475,12 +438,9 @@ export const ResultCard = ({ resultContract, resultData }: Props) => {
id="link-page-result"
value={resultData.content.redirect}
onChange={({ target }: { target: HTMLInputElement }) =>
- updateQuestion(
- resultData.id,
- (question) => {
- question.content.redirect = target.value;
- },
- )
+ updateQuestion(resultData.id, (question) => {
+ question.content.redirect = target.value;
+ })
}
placeholder="https://penahub.ru"
maxLength={200}
diff --git a/src/pages/ResultPage/cards/WhenCard.tsx b/src/pages/ResultPage/cards/WhenCard.tsx
index 52494e68..c469de81 100644
--- a/src/pages/ResultPage/cards/WhenCard.tsx
+++ b/src/pages/ResultPage/cards/WhenCard.tsx
@@ -6,16 +6,7 @@ import { useCurrentQuiz } from "@root/quizes/hooks";
import { SwitchSetting } from "../SwichResult";
import Info from "@icons/Info";
-import {
- Box,
- IconButton,
- Paper,
- Button,
- Typography,
- useMediaQuery,
- useTheme,
- Popover,
-} from "@mui/material";
+import { Box, IconButton, Paper, Button, Typography, useMediaQuery, useTheme, Popover } from "@mui/material";
import ExpandLessIconBG from "@icons/ExpandLessIconBG";
import ExpandLessIcon from "@mui/icons-material/ExpandLess";
@@ -88,10 +79,7 @@ const InfoView = () => {
flexDirection: "column",
}}
>
-
- Oтправка письма с результатом респонденту после отображения на
- экране
-
+ Oтправка письма с результатом респонденту после отображения на экране
>
@@ -190,7 +178,10 @@ export const WhenCard = ({ quizExpand }: Props) => {
}}
>
{whenValues.map(({ title, value, id }, index) => (
-
+
{
@@ -201,32 +192,16 @@ export const WhenCard = ({ quizExpand }: Props) => {
}}
key={title}
sx={{
- bgcolor:
- quiz?.config.resultInfo.showResultForm === value
- ? " #7E2AEA"
- : "#F2F3F7",
- color:
- quiz?.config.resultInfo.showResultForm === value
- ? " white"
- : "#9A9AAF",
- minWidth: isSmallMonitor
- ? isMobile
- ? undefined
- : "310px"
- : "auto",
+ bgcolor: quiz?.config.resultInfo.showResultForm === value ? " #7E2AEA" : "#F2F3F7",
+ color: quiz?.config.resultInfo.showResultForm === value ? " white" : "#9A9AAF",
+ minWidth: isSmallMonitor ? (isMobile ? undefined : "310px") : "auto",
borderRadius: "8px",
width: isMobile ? "100%" : "220px",
height: "44px",
fontSize: "17px",
- border:
- quiz?.config.resultInfo.showResultForm === value
- ? "none"
- : "1px solid #9A9AAF",
+ border: quiz?.config.resultInfo.showResultForm === value ? "none" : "1px solid #9A9AAF",
"&:hover": {
- backgroundColor:
- quiz?.config.resultInfo.showResultForm === value
- ? "#581CA7"
- : "#7E2AEA",
+ backgroundColor: quiz?.config.resultInfo.showResultForm === value ? "#581CA7" : "#7E2AEA",
color: "white",
},
}}
@@ -252,32 +227,16 @@ export const WhenCard = ({ quizExpand }: Props) => {
});
}}
sx={{
- bgcolor:
- quiz?.config.resultInfo.when === "email"
- ? " #7E2AEA"
- : "#F2F3F7",
- color:
- quiz?.config.resultInfo.when === "email"
- ? " white"
- : "#9A9AAF",
- minWidth: isSmallMonitor
- ? isMobile
- ? undefined
- : "310px"
- : "auto",
+ bgcolor: quiz?.config.resultInfo.when === "email" ? " #7E2AEA" : "#F2F3F7",
+ color: quiz?.config.resultInfo.when === "email" ? " white" : "#9A9AAF",
+ minWidth: isSmallMonitor ? (isMobile ? undefined : "310px") : "auto",
borderRadius: "8px",
width: isMobile ? "100%" : "220px",
height: "44px",
fontSize: "17px",
- border:
- quiz?.config.resultInfo.when === "email"
- ? "none"
- : "1px solid #9A9AAF",
+ border: quiz?.config.resultInfo.when === "email" ? "none" : "1px solid #9A9AAF",
"&:hover": {
- backgroundColor:
- quiz?.config.resultInfo.when === "email"
- ? "#581CA7"
- : "#7E2AEA",
+ backgroundColor: quiz?.config.resultInfo.when === "email" ? "#581CA7" : "#7E2AEA",
color: "white",
},
}}
diff --git a/src/pages/startPage/StartPageSettings.tsx b/src/pages/startPage/StartPageSettings.tsx
index 385c4ec5..812d9be6 100755
--- a/src/pages/startPage/StartPageSettings.tsx
+++ b/src/pages/startPage/StartPageSettings.tsx
@@ -27,11 +27,7 @@ import {
useMediaQuery,
useTheme,
} from "@mui/material";
-import {
- incrementCurrentStep,
- updateQuiz,
- uploadQuizImage,
-} from "@root/quizes/actions";
+import { incrementCurrentStep, updateQuiz, uploadQuizImage } from "@root/quizes/actions";
import { useCurrentQuiz } from "@root/quizes/hooks";
import CustomCheckbox from "@ui_kit/CustomCheckbox";
import CustomTextField from "@ui_kit/CustomTextField";
@@ -47,24 +43,12 @@ import { DropZone } from "./dropZone";
import Extra from "./extra";
import TooltipClickInfo from "@ui_kit/Toolbars/TooltipClickInfo";
import { VideoElement } from "./VideoElement";
-import * as React from "react";
+import UploadVideoModal from "../Questions/UploadVideoModal";
const designTypes = [
- [
- "standard",
- (color: string) => ,
- "Standard",
- ],
- [
- "expanded",
- (color: string) => ,
- "Expanded",
- ],
- [
- "centered",
- (color: string) => ,
- "Centered",
- ],
+ ["standard", (color: string) => , "Standard"],
+ ["expanded", (color: string) => , "Expanded"],
+ ["centered", (color: string) => , "Centered"],
] as const;
export default function StartPageSettings() {
@@ -78,12 +62,28 @@ export default function StartPageSettings() {
const [faviconUploding, setFaviconUploading] = useState(false);
const [backgroundUploding, setBackgroundUploading] = useState(false);
const [logoUploding, setLogoUploading] = useState(false);
+ const [isVideoUploadDialogOpen, setIsVideoUploadDialogOpen] = useState(false);
if (!quiz) return null;
- const MobileVersionHC = (bool: boolean) => {
- setMobileVersion(bool);
- };
+ async function handleVideoUpload(videoUrl: string) {
+ 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;
let cropAspectRatio:
@@ -129,6 +129,12 @@ export default function StartPageSettings() {
return (
<>
+ setIsVideoUploadDialogOpen(false)}
+ onUpload={handleVideoUpload}
+ video={quiz.config.startpage.background.video}
+ />
Дизайн
- setFormState("content")}>
+ setFormState("content")}
+ >
Контент
@@ -222,8 +225,7 @@ export default function StartPageSettings() {
displayEmpty
onChange={(e) =>
updateQuiz(quiz.id, (quiz) => {
- quiz.config.startpageType = e.target
- .value as QuizStartpageType;
+ quiz.config.startpageType = e.target.value as QuizStartpageType;
})
}
sx={{
@@ -280,11 +282,7 @@ export default function StartPageSettings() {
color: theme.palette.grey2.main,
}}
>
- {type[1](
- type[0] === designType
- ? theme.palette.orange.main
- : theme.palette.grey2.main,
- )}
+ {type[1](type[0] === designType ? theme.palette.orange.main : theme.palette.grey2.main)}
{type[2]}
))}
@@ -331,10 +329,7 @@ export default function StartPageSettings() {
{quiz.config.startpage.background.type === "image" && (
@@ -368,15 +363,12 @@ export default function StartPageSettings() {
sx={{ maxWidth: "300px" }}
cropAspectRatio={cropAspectRatio}
imageUrl={quiz.config.startpage.background.desktop}
- originalImageUrl={
- quiz.config.startpage.background.originalDesktop
- }
+ originalImageUrl={quiz.config.startpage.background.originalDesktop}
onImageUploadClick={async (file) => {
setBackgroundUploading(true);
await uploadQuizImage(quiz.id, file, (quiz, url) => {
quiz.config.startpage.background.desktop = url;
- quiz.config.startpage.background.originalDesktop =
- url;
+ quiz.config.startpage.background.originalDesktop = url;
});
setBackgroundUploading(false);
@@ -426,7 +418,10 @@ export default function StartPageSettings() {
{isMobile ? (
) : (
-
+
@@ -445,7 +440,7 @@ export default function StartPageSettings() {
) : (
<>
setIsVideoUploadDialogOpen(true)}
sx={{
justifyContent: "center",
height: "48px",
@@ -455,29 +450,6 @@ export default function StartPageSettings() {
my: "20px",
}}
>
- {
- 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"
- />
}
sx={{
@@ -559,10 +531,7 @@ export default function StartPageSettings() {
<>
@@ -641,10 +610,7 @@ export default function StartPageSettings() {
<>
@@ -870,22 +836,24 @@ export default function StartPageSettings() {
maxLength={1000}
/>
-
- {
- updateQuiz(quiz.id, (quiz) => {
- quiz.config.antifraud = e.target.checked;
-
- })
- }}
- />
-
- Включить антифрод
-
-
+
+ {
+ updateQuiz(quiz.id, (quiz) => {
+ quiz.config.antifraud = e.target.checked;
+ });
+ }}
+ />
+
+ Включить антифрод
+
+
>
)}
diff --git a/src/pages/startPage/VideoElement.tsx b/src/pages/startPage/VideoElement.tsx
index cd3d8e8a..5be6618a 100644
--- a/src/pages/startPage/VideoElement.tsx
+++ b/src/pages/startPage/VideoElement.tsx
@@ -2,6 +2,7 @@ import Box from "@mui/material/Box";
import { FC } from "react";
import DeleteIcon from "@mui/icons-material/Delete";
import { IconButton, SxProps, Theme } from "@mui/material";
+import { QuizVideo } from "@frontend/squzanswerer";
type VideoElementProps = {
videoSrc: string;
@@ -20,12 +21,7 @@ export const VideoElement: FC = ({
}) => {
return (
-
+
{
type: "setEditQuizId",
quizId,
- },
+ }
);
export const resetEditConfig = () =>
@@ -37,7 +37,7 @@ export const setQuizes = (quizes: RawQuiz[] | null) =>
{
type: "setQuizes",
quizes,
- },
+ }
);
const addQuiz = (quiz: Quiz) =>
@@ -48,7 +48,7 @@ const addQuiz = (quiz: Quiz) =>
{
type: "addQuiz",
quiz,
- },
+ }
);
const removeQuiz = (quizId: string) =>
@@ -62,7 +62,7 @@ const removeQuiz = (quizId: string) =>
{
type: "removeQuiz",
quizId,
- },
+ }
);
const setQuizBackendId = (quizId: string, backendId: number) =>
@@ -77,20 +77,17 @@ const setQuizBackendId = (quizId: string, backendId: number) =>
type: "setQuizBackendId",
quizId,
backendId,
- },
+ }
);
export const incrementCurrentStep = () =>
setProducedState(
(state) => {
- state.currentStep = Math.min(
- maxQuizSetupSteps - 1,
- state.currentStep + 1,
- );
+ state.currentStep = Math.min(maxQuizSetupSteps - 1, state.currentStep + 1);
},
{
type: "incrementCurrentStep",
- },
+ }
);
export const decrementCurrentStep = () =>
@@ -100,7 +97,7 @@ export const decrementCurrentStep = () =>
},
{
type: "decrementCurrentStep",
- },
+ }
);
export const setCurrentStep = (step: number) =>
@@ -111,7 +108,7 @@ export const setCurrentStep = (step: number) =>
{
type: "setCurrentStep",
step,
- },
+ }
);
export const setQuizType = (quizId: string, quizType: QuizConfig["type"]) => {
@@ -120,10 +117,7 @@ export const setQuizType = (quizId: string, quizType: QuizConfig["type"]) => {
});
};
-export const setQuizStartpageType = (
- quizId: string,
- startpageType: QuizConfig["startpageType"],
-) => {
+export const setQuizStartpageType = (quizId: string, startpageType: QuizConfig["startpageType"]) => {
updateQuiz(quizId, (quiz) => {
quiz.config.startpageType = startpageType;
});
@@ -133,10 +127,7 @@ const REQUEST_DEBOUNCE = 200;
const requestQueue = new RequestQueue();
let requestTimeoutId: ReturnType;
-export const updateQuiz = (
- quizId: string | null | undefined,
- updateFn: (quiz: Quiz) => void,
-) => {
+export const updateQuiz = (quizId: string | null | undefined, updateFn: (quiz: Quiz) => void) => {
if (!quizId) return;
setProducedState(
@@ -150,7 +141,7 @@ export const updateQuiz = (
type: "updateQuiz",
quizId,
updateFn: updateFn.toString(),
- },
+ }
);
clearTimeout(requestTimeoutId);
@@ -159,9 +150,7 @@ export const updateQuiz = (
const quiz = useQuizStore.getState().quizes.find((q) => q.id === quizId);
if (!quiz) return;
- const [editedQuiz, editedQuizError] = await quizApi.edit(
- quizToEditQuizRequest(quiz),
- );
+ const [editedQuiz, editedQuizError] = await quizApi.edit(quizToEditQuizRequest(quiz));
if (editedQuizError || !editedQuiz) {
devlog("Error editing quiz", editedQuizError, quizId);
@@ -270,22 +259,15 @@ export const copyQuiz = async (quizId: string) =>
(state) => {
state.quizes.unshift(newQuiz);
},
- { type: "addQuiz", quiz },
+ { type: "addQuiz", quiz }
);
});
-export const uploadQuizImage = async (
- quizId: string,
- blob: Blob,
- updateFn: (quiz: Quiz, imageId: string) => void,
-) => {
+export const uploadQuizImage = async (quizId: string, blob: Blob, updateFn: (quiz: Quiz, imageId: string) => void) => {
const quiz = useQuizStore.getState().quizes.find((q) => q.id === quizId);
if (!quiz) return;
- const [addedImages, addImagesError] = await quizApi.addImages(
- quiz.backendId,
- blob,
- );
+ const [addedImages, addImagesError] = await quizApi.addImages(quiz.backendId, blob);
if (addImagesError || !addedImages) {
devlog("Error uploading quiz image", addImagesError);
@@ -305,14 +287,11 @@ export const uploadQuizImage = async (
updateQuiz(quizId, (quiz) => {
updateFn(
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(
- recipe: (state: QuizStore) => void,
- action?: A,
-) {
+function setProducedState(recipe: (state: QuizStore) => void, action?: A) {
useQuizStore.setState((state) => produce(state, recipe), false, action);
}
diff --git a/src/ui_kit/AddOrEditImageButton.tsx b/src/ui_kit/AddOrEditImageButton.tsx
index e7a4316a..83861d65 100644
--- a/src/ui_kit/AddOrEditImageButton.tsx
+++ b/src/ui_kit/AddOrEditImageButton.tsx
@@ -6,19 +6,13 @@ import type { SxProps, Theme } from "@mui/material";
interface Props {
sx?: SxProps;
- imageSrc?: string;
+ imageSrc?: string | null;
onImageClick?: () => void;
onPlusClick?: () => void;
uploading: boolean;
}
-export default function AddOrEditImageButton({
- onImageClick,
- onPlusClick,
- sx,
- imageSrc,
- uploading = false,
-}: Props) {
+export default function AddOrEditImageButton({ onImageClick, onPlusClick, sx, imageSrc, uploading = false }: Props) {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(790));
diff --git a/src/ui_kit/MediaSelectionAndDisplay.tsx b/src/ui_kit/MediaSelectionAndDisplay.tsx
index bd2d6665..22660725 100644
--- a/src/ui_kit/MediaSelectionAndDisplay.tsx
+++ b/src/ui_kit/MediaSelectionAndDisplay.tsx
@@ -1,64 +1,44 @@
-import { FC, useState } from "react";
-import {
- 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 { QuizQuestionPage } from "@/model/questionTypes/page";
+import { QuizQuestionResult } from "@/model/questionTypes/result";
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 { useCurrentQuiz } from "../stores/quizes/hooks";
+import { useDisclosure } from "../utils/useDisclosure";
+import UploadVideoModal from "@/pages/Questions/UploadVideoModal";
-interface Iprops {
- resultData: AnyTypedQuizQuestion;
+interface Props {
+ question: QuizQuestionPage | QuizQuestionResult;
cropAspectRatio: {
width: number;
height: number;
};
}
-export const MediaSelectionAndDisplay: FC = ({
- resultData,
- cropAspectRatio,
-}) => {
+export const MediaSelectionAndDisplay: FC = ({ question, cropAspectRatio }) => {
const [pictureUploding, setPictureUploading] = useState(false);
const [backgroundUploding, setBackgroundUploading] = useState(false);
const quizQid = useCurrentQuiz()?.qid;
const theme = useTheme();
- const {
- isCropModalOpen,
- openCropModal,
- closeCropModal,
- imageBlob,
- originalImageUrl,
- setCropModalImageBlob,
- } = useCropModalState();
- const [isImageUploadOpen, openImageUploadModal, closeImageUploadModal] =
- useDisclosure();
+ const { isCropModalOpen, openCropModal, closeCropModal, imageBlob, originalImageUrl, setCropModalImageBlob } =
+ useCropModalState();
+ const [isImageUploadOpen, openImageUploadModal, closeImageUploadModal] = useDisclosure();
+ const [isVideoUploadDialogOpen, setIsVideoUploadDialogOpen] = useState(false);
+
async function handleImageUpload(file: File) {
setPictureUploading(true);
- const url = await uploadQuestionImage(
- resultData.id,
- quizQid,
- file,
- (question, url) => {
- question.content.back = url;
- question.content.originalBack = url;
- },
- );
+ const url = await uploadQuestionImage(question.id, quizQid, file, (question, url) => {
+ question.content.back = url;
+ question.content.originalBack = url;
+ });
closeImageUploadModal();
openCropModal(file, url);
@@ -66,11 +46,32 @@ export const MediaSelectionAndDisplay: FC = ({
}
function handleCropModalSaveClick(imageBlob: Blob) {
- uploadQuestionImage(resultData.id, quizQid, imageBlob, (question, url) => {
+ uploadQuestionImage(question.id, quizQid, imageBlob, (question, 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 (
= ({
>
= ({
}}
variant="text"
onClick={() =>
- updateQuestion(
- resultData.id,
- (question) => (question.content.useImage = true),
- )
+ updateQuestion(question.id, (question) => {
+ if (!("useImage" in question.content)) return;
+
+ question.content.useImage = true;
+ })
}
>
Изображение
= ({
}}
variant="text"
onClick={() =>
- updateQuestion(
- resultData.id,
- (question) => (question.content.useImage = false),
- )
+ updateQuestion(question.id, (question) => {
+ if (!("useImage" in question.content)) return;
+
+ question.content.useImage = false;
+ })
}
>
Видео
-
-
+ {
+ updateQuestion(question.id, (question) => {
+ question.content.back = null;
+ question.content.originalBack = null;
+ });
}}
- >
-
- {
- updateQuestion(resultData.id, (question) => {
- question.content.back = null;
- question.content.originalBack = null;
- });
- }}
- cropAspectRatio={cropAspectRatio}
- />
-
-
- {resultData.content.useImage && (
+ cropAspectRatio={cropAspectRatio}
+ />
+ setIsVideoUploadDialogOpen(false)}
+ onUpload={handleVideoUpload}
+ video={question.content.video}
+ />
+ {question.content.useImage && (
= ({
}}
>
{
- if (resultData.content.back) {
- return openCropModal(
- resultData.content.back,
- resultData.content.originalBack,
- );
+ if (question.content.back) {
+ return openCropModal(question.content.back, question.content.originalBack);
}
openImageUploadModal();
@@ -180,9 +177,9 @@ export const MediaSelectionAndDisplay: FC = ({
/>
)}
- {!resultData.content.useImage && (
+ {!question.content.useImage && (
<>
- {!resultData.content.video ? (
+ {!question.content.video ? (
<>
= ({
mb: "14px",
}}
>
- Добавить видео
+
- Добавить видео
-
-
@@ -216,7 +212,7 @@ export const MediaSelectionAndDisplay: FC = ({
) : (
<>
setIsVideoUploadDialogOpen(true)}
sx={{
justifyContent: "center",
height: "48px",
@@ -226,27 +222,6 @@ export const MediaSelectionAndDisplay: FC = ({
my: "20px",
}}
>
- {
- 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"
- />
}
sx={{
@@ -260,10 +235,12 @@ export const MediaSelectionAndDisplay: FC = ({
>
) : (
{
- updateQuestion(resultData.id, (question) => {
+ updateQuestion(question.id, (question) => {
+ if (!("video" in question.content)) return;
+
question.content.video = null;
});
}}
diff --git a/yarn.lock b/yarn.lock
index 4c857be4..1bda485d 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1521,10 +1521,10 @@
immer "^10.0.2"
reconnecting-eventsource "^1.6.2"
-"@frontend/squzanswerer@^1.0.44":
- version "1.0.44"
- resolved "https://penahub.gitlab.yandexcloud.net/api/v4/projects/43/packages/npm/@frontend/squzanswerer/-/@frontend/squzanswerer-1.0.44.tgz#12c19b23a1e1eff4d0cbfeffbc9ed1160c49cde2"
- integrity sha1-EsGbI6Hh7/TQy/7/vJ7RFgxJzeI=
+"@frontend/squzanswerer@^1.0.45":
+ version "1.0.45"
+ resolved "https://penahub.gitlab.yandexcloud.net/api/v4/projects/43/packages/npm/@frontend/squzanswerer/-/@frontend/squzanswerer-1.0.45.tgz#1124aaa099034b0b75eda7b5c91f457db47872ab"
+ integrity sha1-ESSqoJkDSwt17ae1yR9FfbR4cqs=
dependencies:
bowser "1.9.4"
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"
integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==
-"string-width-cjs@npm: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:
+"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==
@@ -10662,14 +10653,7 @@ stringify-object@^3.3.0:
is-obj "^1.0.1"
is-regexp "^1.0.0"
-"strip-ansi-cjs@npm: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:
+"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==
@@ -11856,7 +11840,7 @@ workbox-window@6.6.1:
"@types/trusted-types" "^2.0.2"
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"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
@@ -11874,15 +11858,6 @@ wrap-ansi@^6.2.0:
string-width "^4.1.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:
version "8.1.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"