add image crop modal to page question settings

This commit is contained in:
nflnkr 2023-10-24 16:02:09 +03:00
parent 66b39f63de
commit fe616ecf3a
4 changed files with 85 additions and 110 deletions

@ -11,6 +11,7 @@ export const QUIZ_QUESTION_PAGE: Omit<QuizQuestionPage, "id"> = {
innerName: "", innerName: "",
text: "", text: "",
picture: "", picture: "",
originalPicture: "",
video: "", video: "",
}, },
}; };

@ -13,6 +13,7 @@ export interface QuizQuestionPage extends QuizQuestionBase {
innerName: string; innerName: string;
text: string; text: string;
picture: string; picture: string;
originalPicture: string;
video: string; video: string;
hint: QuestionHint; hint: QuestionHint;
rule: QuestionBranchingRule; rule: QuestionBranchingRule;

@ -1,9 +1,8 @@
import { ImageAddIcons } from "@icons/ImageAddIcons";
import { VideofileIcon } from "@icons/questionsPage/VideofileIcon"; import { VideofileIcon } from "@icons/questionsPage/VideofileIcon";
import { Box, Typography, useMediaQuery, useTheme } from "@mui/material"; import { Box, Typography, useMediaQuery, useTheme } from "@mui/material";
import { questionStore, updateQuestionsList } from "@root/questions"; import { questionStore, setPageQuestionOriginalPicture, setPageQuestionPicture, updateQuestionsList } from "@root/questions";
import CustomTextField from "@ui_kit/CustomTextField"; import CustomTextField from "@ui_kit/CustomTextField";
import { useEffect, useState } from "react"; import { useState } from "react";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import { useDebouncedCallback } from "use-debounce"; import { useDebouncedCallback } from "use-debounce";
import ButtonsOptions from "../ButtonsOptions"; import ButtonsOptions from "../ButtonsOptions";
@ -11,6 +10,9 @@ import { UploadImageModal } from "../UploadImage/UploadImageModal";
import { UploadVideoModal } from "../UploadVideoModal"; import { UploadVideoModal } from "../UploadVideoModal";
import SwitchPageOptions from "./switchPageOptions"; import SwitchPageOptions from "./switchPageOptions";
import { openCropModal } from "@root/cropModal";
import AddOrEditImageButton from "@ui_kit/AddOrEditImageButton";
import { CropModal } from "@ui_kit/Modal/CropModal";
import type { QuizQuestionPage } from "../../../model/questionTypes/page"; import type { QuizQuestionPage } from "../../../model/questionTypes/page";
type Props = { type Props = {
@ -39,6 +41,21 @@ export default function PageOptions({ disableInput, totalIndex }: Props) {
setSwitchState(data); setSwitchState(data);
}; };
function handleImageUpload(fileList: FileList | null) {
if (!fileList?.length) return;
const url = URL.createObjectURL(fileList[0]);
setPageQuestionPicture(quizId, totalIndex, url);
setPageQuestionOriginalPicture(quizId, totalIndex, url);
setOpenImageModal(false);
openCropModal(url, url);
}
function handleCropModalSaveClick(url: string) {
setPageQuestionPicture(quizId, totalIndex, url);
}
return ( return (
<> <>
<Box <Box
@ -70,7 +87,6 @@ export default function PageOptions({ disableInput, totalIndex }: Props) {
}} }}
> >
<Box <Box
onClick={() => setOpenImageModal(true)}
sx={{ sx={{
cursor: "pointer", cursor: "pointer",
display: "flex", display: "flex",
@ -78,101 +94,22 @@ export default function PageOptions({ disableInput, totalIndex }: Props) {
gap: "20px", gap: "20px",
}} }}
> >
{isMobile ? ( <AddOrEditImageButton
<Box imageSrc={question.content.picture}
sx={{ onImageClick={() => {
display: "flex", if (question.content.picture) {
alignItems: "center", return openCropModal(
width: "120px", question.content.picture,
position: "relative", question.content.originalPicture
}} );
> }
<Box
sx={{ setOpenImageModal(true);
width: "100%", }}
background: "#EEE4FC", onPlusClick={() => {
height: "40px", setOpenImageModal(true);
display: "flex", }}
alignItems: "center", />
justifyContent: "center",
borderTopLeftRadius: "4px",
borderBottomLeftRadius: "4px",
}}
>
{question.content.picture ? (
<Box sx={{ display: "flex", width: "40px" }}>
<img
src={question.content.picture}
alt=""
style={{ width: "100%" }}
/>
</Box>
) : (
<ImageAddIcons
style={{
color: "#7E2AEA",
fontSize: "20px",
}}
/>
)}
</Box>
<Box
sx={{
display: "flex",
justifyContent: "center",
alignItems: "center",
width: "20px",
background: "#EEE4FC",
height: "40px",
color: "white",
backgroundColor: "#7E2AEA",
borderTopRightRadius: "4px",
borderBottomRightRadius: "4px",
}}
>
+
</Box>
</Box>
) : (
<Box
sx={{
width: "60px",
height: "40px",
background: "#EEE4FC",
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
>
{question.content.picture ? (
<Box sx={{ display: "flex", width: "40px" }}>
<img
src={question.content.picture}
alt=""
style={{ width: "100%" }}
/>
</Box>
) : (
<Box sx={{ display: "flex", alignItems: "center", justifyContent: "center", width: "100%" }}>
<ImageAddIcons fontSize="22px" color="#7E2AEA" />
</Box>
)}
<span
style={{
display: "flex",
alignItems: "center",
justifyContent: "center",
background: "#7E2AEA",
height: "100%",
width: "25px",
color: "white",
fontSize: "15px",
}}
>
+
</span>
</Box>
)}
<Typography <Typography
sx={{ sx={{
@ -189,18 +126,9 @@ export default function PageOptions({ disableInput, totalIndex }: Props) {
<UploadImageModal <UploadImageModal
open={openImageModal} open={openImageModal}
onClose={() => setOpenImageModal(false)} onClose={() => setOpenImageModal(false)}
imgHC={(fileList) => { imgHC={handleImageUpload}
if (fileList?.length) {
updateQuestionsList<QuizQuestionPage>(quizId, totalIndex, {
content: {
...question.content,
picture: URL.createObjectURL(fileList[0]),
},
});
}
}}
// onClick={() => setOpenVideoModal(true)}
/> />
<CropModal onSaveImageClick={handleCropModalSaveClick} />
<Typography> или</Typography> <Typography> или</Typography>
<Box <Box
sx={{ sx={{

@ -120,6 +120,21 @@ export const updateQuestionsList = <T = AnyQuizQuestion>(
questionStore.setState({ listQuestions: questionListClone }); questionStore.setState({ listQuestions: questionListClone });
}; };
export const updateQuestion = <T extends AnyQuizQuestion>(
quizId: number,
questionIndex: number,
recipe: (question: T) => void,
) => setProducedState(state => {
const question = state.listQuestions[quizId][questionIndex] as T;
recipe(question);
}, {
type: "updateQuestion",
quizId,
questionIndex,
recipe,
});
export const removeQuestionsByQuizId = (quizId: number) => setProducedState(state => { export const removeQuestionsByQuizId = (quizId: number) => setProducedState(state => {
delete state.listQuestions[quizId]; delete state.listQuestions[quizId];
}, "removeQuestionsByQuizId"); }, "removeQuestionsByQuizId");
@ -172,6 +187,36 @@ export const setVariantOriginalImageUrl = (
url, url,
}); });
export const setPageQuestionPicture = (
quizId: number,
questionIndex: number,
url: string,
) => setProducedState(state => {
const question = state.listQuestions[quizId][questionIndex];
if (question.type !== "page") return;
if (question.content.picture === url) return;
if (
question.content.picture !== question.content.originalPicture
) URL.revokeObjectURL(question.content.picture);
question.content.picture = url;
});
export const setPageQuestionOriginalPicture = (
quizId: number,
questionIndex: number,
url: string,
) => setProducedState(state => {
const question = state.listQuestions[quizId][questionIndex];
if (question.type !== "page") return;
if (question.content.originalPicture === url) return;
URL.revokeObjectURL(question.content.originalPicture);
question.content.originalPicture = url;
});
export const updateQuestionsListDragAndDrop = ( export const updateQuestionsListDragAndDrop = (
quizId: number, quizId: number,
updatedQuestions: AnyQuizQuestion[] updatedQuestions: AnyQuizQuestion[]