варианты с картинками открывают кроп

This commit is contained in:
Nastya 2024-11-13 07:40:31 +03:00
parent ba32cce126
commit 9c78e245c3
7 changed files with 142 additions and 79 deletions

@ -96,6 +96,7 @@ export type Writable<T> = { -readonly [K in keyof T]: T[K] };
export type CropOnOpenType = { export type CropOnOpenType = {
open: boolean;
originalImageUrl?:string; originalImageUrl?:string;
imageBlob?: Blob; imageBlob?: Blob;
editedUrlImagesList?: Record<Partial<ScreenStepsTypes>, string>; editedUrlImagesList?: Record<Partial<ScreenStepsTypes>, string>;
@ -103,12 +104,13 @@ export type CropOnOpenType = {
questionType: AcceptedQuestionTypes; questionType: AcceptedQuestionTypes;
quizId: string; quizId: string;
selfClose?: () => void; selfClose: () => void;
setPictureUploading?: (is: boolean) => void; setPictureUploading: (is: boolean) => void;
} }
export type WorkSpaceTypes = WorkSpaceTypesList[AcceptedQuestionTypes]; export type WorkSpaceTypes = WorkSpaceTypesList[AcceptedQuestionTypes];
export interface CropModalProps { export interface CropModalProps {
open: boolean;
editedImages: Record<keyof WorkSpaceTypes, EditedImage>; editedImages: Record<keyof WorkSpaceTypes, EditedImage>;
workSpaceTypes: WorkSpaceTypes; workSpaceTypes: WorkSpaceTypes;
originalImageUrl: string; originalImageUrl: string;

@ -30,6 +30,8 @@ export default function OptionsAndPicture({
}: Props) { }: Props) {
const [switchState, setSwitchState] = useState("setting"); const [switchState, setSwitchState] = useState("setting");
const [pictureUploding, setPictureUploading] = useState<boolean>(false); const [pictureUploding, setPictureUploading] = useState<boolean>(false);
const [openCropModal, setOpenCropModal] = useState(false);
const [selectedVariantId, setSelectedVariantId] = useState<string | null>( const [selectedVariantId, setSelectedVariantId] = useState<string | null>(
null, null,
); );
@ -122,6 +124,9 @@ export default function OptionsAndPicture({
questionId={question.backendId.toString()} questionId={question.backendId.toString()}
questionType={question.type} questionType={question.type}
quizId={quizQid} quizId={quizQid}
open={openCropModal}
selfClose={() => setOpenCropModal(false)}
setPictureUploading={setPictureUploading}
/> />
<Box <Box
sx={{ sx={{

@ -4,7 +4,7 @@ import {
uploadQuestionImage, uploadQuestionImage,
} from "@root/questions/actions"; } from "@root/questions/actions";
import { useCurrentQuiz } from "@root/quizes/hooks"; import { useCurrentQuiz } from "@root/quizes/hooks";
import { useState } from "react"; import { useMemo, useState } from "react";
import { EnterIcon } from "../../../assets/icons/questionsPage/enterIcon"; import { EnterIcon } from "../../../assets/icons/questionsPage/enterIcon";
import type { QuizQuestionImages } from "../../../model/questionTypes/images"; import type { QuizQuestionImages } from "../../../model/questionTypes/images";
import { useAddAnswer } from "../../../utils/hooks/useAddAnswer"; import { useAddAnswer } from "../../../utils/hooks/useAddAnswer";
@ -32,19 +32,25 @@ export default function OptionsPicture({
const onClickAddAnAnswer = useAddAnswer(); const onClickAddAnAnswer = useAddAnswer();
const quizQid = useCurrentQuiz()?.qid; const quizQid = useCurrentQuiz()?.qid;
const [pictureUploding, setPictureUploading] = useState<boolean>(false); const [pictureUploding, setPictureUploading] = useState<boolean>(false);
const [selectedVariantId, setSelectedVariantId] = useState<string | null>( const [openCropModal, setOpenCropModal] = useState(false);
null,
); const [selectedVariantId, setSelectedVariantId] = useState<string | null>(null);
const variant = useMemo(() => question.content.variants.find(
(variant) => variant.id === selectedVariantId,
),[selectedVariantId])
const [switchState, setSwitchState] = useState("setting"); const [switchState, setSwitchState] = useState("setting");
const isMobile = useMediaQuery(theme.breakpoints.down(790)); const isMobile = useMediaQuery(theme.breakpoints.down(790));
const [isImageUploadOpen, openImageUploadModal, closeImageUploadModal] = const [isImageUploadOpen, openImageUploadModal, closeImageUploadModal] = useDisclosure();
useDisclosure();
console.log(variant)
const handleImageUpload = async (file: File) => { const handleImageUpload = async (file: File) => {
if (!selectedVariantId) return; if (!selectedVariantId) return;
setPictureUploading(true); setPictureUploading(true);
closeImageUploadModal();
const url = await uploadQuestionImage( const url = await uploadQuestionImage(
question.id, question.id,
quizQid, quizQid,
@ -62,26 +68,11 @@ export default function OptionsPicture({
}, },
); );
closeImageUploadModal(); setOpenCropModal(true)
setPictureUploading(false); setPictureUploading(false);
}; };
function handleCropModalSaveClick(imageBlob: Blob) {
if (!selectedVariantId) return;
uploadQuestionImage(question.id, quizQid, imageBlob, (question, url) => {
if (!("variants" in question.content)) return;
const variant = question.content.variants.find(
(variant) => variant.id === selectedVariantId,
);
if (!variant) return;
variant.extendedText = url;
});
}
return ( return (
<> <>
<Box sx={{ padding: "20px" }}> <Box sx={{ padding: "20px" }}>
@ -96,7 +87,7 @@ export default function OptionsPicture({
largeCheck={question.content.largeCheck} largeCheck={question.content.largeCheck}
variant={variant} variant={variant}
isMobile={isMobile} isMobile={isMobile}
openCropModal={()=>{}} openCropModal={() => {setOpenCropModal(true)}}
openImageUploadModal={openImageUploadModal} openImageUploadModal={openImageUploadModal}
pictureUploding={pictureUploding} pictureUploding={pictureUploding}
setSelectedVariantId={setSelectedVariantId} setSelectedVariantId={setSelectedVariantId}
@ -109,16 +100,14 @@ export default function OptionsPicture({
handleImageChange={handleImageUpload} handleImageChange={handleImageUpload}
/> />
<CropModalInit <CropModalInit
originalImageUrl={imge} originalImageUrl={variant?.originalImageUrl}
editedUrlImagesList={{ editedUrlImagesList={variant?.editedUrlImagesList}
"desktop": imge,
"tablet": imge,
"mobile": imge,
"small": imge,
}}
questionId={question.backendId.toString()} questionId={question.backendId.toString()}
questionType={question.type} questionType={question.type}
quizId={quizQid} quizId={quizQid}
open={openCropModal}
selfClose={() => setOpenCropModal(false)}
setPictureUploading={setPictureUploading}
/> />
<Box sx={{ display: "flex", alignItems: "center", gap: "10px" }}> <Box sx={{ display: "flex", alignItems: "center", gap: "10px" }}>
<Link <Link

@ -47,6 +47,10 @@ export const DropZone = ({
}: Props) => { }: Props) => {
const theme = useTheme(); const theme = useTheme();
const quiz = useCurrentQuiz(); const quiz = useCurrentQuiz();
const [pictureUploding, setPictureUploading] = useState<boolean>(false);
const [openCropModal, setOpenCropModal] = useState(false);
const [isDropReady, setIsDropReady] = useState<boolean>(false); const [isDropReady, setIsDropReady] = useState<boolean>(false);
const [isImageUploadOpen, openImageUploadModal, closeImageUploadModal] = const [isImageUploadOpen, openImageUploadModal, closeImageUploadModal] =
useDisclosure(); useDisclosure();
@ -104,7 +108,10 @@ export const DropZone = ({
}} }}
questionId={'2'} questionId={'2'}
questionType={"images"} questionType={"images"}
quizId={"12"} quizId={quiz.id}
open={openCropModal}
selfClose={() => setOpenCropModal(false)}
setPictureUploading={setPictureUploading}
/> />
<ButtonBase <ButtonBase
onClick={ openImageUploadModal onClick={ openImageUploadModal

@ -37,6 +37,7 @@ export const MediaSelectionAndDisplay: FC<Iprops> = ({
}) => { }) => {
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 [openCropModal, setOpenCropModal] = useState(false);
const quizQid = useCurrentQuiz()?.qid; const quizQid = useCurrentQuiz()?.qid;
const theme = useTheme(); const theme = useTheme();
const [isImageUploadOpen, openImageUploadModal, closeImageUploadModal] = const [isImageUploadOpen, openImageUploadModal, closeImageUploadModal] =
@ -151,7 +152,7 @@ export const MediaSelectionAndDisplay: FC<Iprops> = ({
mb: "30px", mb: "30px",
}} }}
> >
<AddOrEditImageButton {/* <AddOrEditImageButton
imageSrc={resultData.content.back} imageSrc={resultData.content.back}
uploading={pictureUploding} uploading={pictureUploding}
onImageClick={() => { onImageClick={() => {
@ -167,7 +168,7 @@ export const MediaSelectionAndDisplay: FC<Iprops> = ({
onPlusClick={() => { onPlusClick={() => {
openImageUploadModal(); openImageUploadModal();
}} }}
/> /> */}
</Box> </Box>
)} )}
{!resultData.content.useImage && ( {!resultData.content.useImage && (

@ -22,6 +22,7 @@ const PriorityOfSteps = ["desktop", "tablet", "mobile", "small"];
export type EditedImagesChangeType = (changed: (old: EditedImage) => Partial<EditedImage>) => void; export type EditedImagesChangeType = (changed: (old: EditedImage) => Partial<EditedImage>) => void;
export const CropModal: FC<CropModalProps> = ({ export const CropModal: FC<CropModalProps> = ({
open,
editedImages, editedImages,
workSpaceTypes, workSpaceTypes,
originalImageUrl, originalImageUrl,
@ -59,7 +60,7 @@ export const CropModal: FC<CropModalProps> = ({
return ( return (
<Modal <Modal
open open={open}
onClose={closeCropModal} onClose={closeCropModal}
> >
<Box <Box

@ -16,6 +16,7 @@ import AlertModalDeleteImage from "./AlertModalDeleteImage"
import { getModifiedImageBlob } from "./utils/imageManipulation"; import { getModifiedImageBlob } from "./utils/imageManipulation";
export const CropModalInit: FC<CropOnOpenType> = ({ export const CropModalInit: FC<CropOnOpenType> = ({
open,
originalImageUrl, originalImageUrl,
imageBlob, imageBlob,
editedUrlImagesList, editedUrlImagesList,
@ -26,6 +27,15 @@ export const CropModalInit: FC<CropOnOpenType> = ({
selfClose, selfClose,
setPictureUploading, setPictureUploading,
}) => { }) => {
console.log(
open,
originalImageUrl,
imageBlob,
editedUrlImagesList,
questionId,
questionType,
quizId,
)
const [acceptedOriginalImageUrl, setOriginalImageUrl] = useState(""); const [acceptedOriginalImageUrl, setOriginalImageUrl] = useState("");
const [editedImages, setEditedImages] = useState<Record<keyof WorkSpaceTypes, EditedImage> | null>(null); const [editedImages, setEditedImages] = useState<Record<keyof WorkSpaceTypes, EditedImage> | null>(null);
@ -34,77 +44,99 @@ export const CropModalInit: FC<CropOnOpenType> = ({
console.log(editedImages) console.log(editedImages)
useEffect(() => { useEffect(() => {
//Если нам не дали с чем работать, то и работать не нужно if (open) {
if (Boolean(imageBlob) || Boolean(originalImageUrl)) { console.log("дали ли на ссылочку? ", Boolean(originalImageUrl))
(async () => { //Если нам не дали с чем работать, то и работать не нужно
let newImageBlob = imageBlob; if (Boolean(imageBlob) || Boolean(originalImageUrl)) {
if (originalImageUrl !== undefined) { (async () => {
const response = await fetch(originalImageUrl, { let newImageBlob = imageBlob;
mode: 'no-cors', if (originalImageUrl !== undefined) {
}); const response = await fetch(originalImageUrl, {
newImageBlob = await response.blob(); mode: 'no-cors',
}; });
newImageBlob = await response.blob();
};
if (newImageBlob) { if (newImageBlob) {
const isGif = await isImageBlobAGifFile(newImageBlob); console.log("попытки пытки 0")
if (isGif) { const isGif = await isImageBlobAGifFile(newImageBlob);
saveImagesAndRules(newImageBlob); if (isGif) {
return; saveImagesAndRules(newImageBlob);
} return;
//Для работы нам нужны урлы. Оригинальной и редактированных картинок }
let newOriginalImageUrl = originalImageUrl || URL.createObjectURL(newImageBlob) //Для работы нам нужны урлы. Оригинальной и редактированных картинок
if (questionId) { let newOriginalImageUrl = originalImageUrl || URL.createObjectURL(newImageBlob)
if (questionType) { if (questionId) {
if (Boolean(editedUrlImagesList)) { console.log("попытки пытки 1")
if (questionType) {
const workSpaceTypesCONST = workSpaceTypesList[questionType];
const workSpaceTypesCONST = workSpaceTypesList[questionType] type WritableWorkSpaceTypesCONST = Writable<typeof workSpaceTypesCONST>;
type WritableWorkSpaceTypesCONST = Writable<typeof workSpaceTypesCONST>
const writableEditedImagesList: WritableWorkSpaceTypesCONST = { ...workSpaceTypesList[questionType] }; // Теперь object не readonly const writableEditedImagesList: WritableWorkSpaceTypesCONST = { ...workSpaceTypesList[questionType] }; // Теперь object не readonly
type Keys = keyof typeof writableEditedImagesList; type Keys = keyof typeof writableEditedImagesList;
const newEditedImagesList = {} as Record<Keys, EditedImage>; const newEditedImagesList = {} as Record<Keys, EditedImage>;
for (let k in editedUrlImagesList) {
let key = k as Keys;
if (key in writableEditedImagesList) { //Если вопрос умничка и знает что ему нужно
newEditedImagesList[key] = { if (Boolean(editedUrlImagesList)) {
...writableEditedImagesList[key],
url: editedUrlImagesList[key],
newRules: DEFAULTCROPRULES for (let k in editedUrlImagesList) {
} as EditedImage; let key = k as Keys;
if (key in writableEditedImagesList) {
newEditedImagesList[key] = {
...writableEditedImagesList[key],
url: editedUrlImagesList[key] ?? originalImageUrl,
newRules: DEFAULTCROPRULES
} as EditedImage;
}
}
} else { // Если в первый раз, то создаём ему бланк
for (let k in workSpaceTypesCONST) {
let key = k as Keys;
if (key in writableEditedImagesList) {
newEditedImagesList[key] = {
...writableEditedImagesList[key],
url: originalImageUrl,
newRules: DEFAULTCROPRULES
} as EditedImage;
}
} }
} }
setOriginalImageUrl(newOriginalImageUrl); setOriginalImageUrl(newOriginalImageUrl);
setEditedImages(newEditedImagesList); setEditedImages(newEditedImagesList);
console.log("попытки пытки ")
} else {
throw new Error("Не передан тип вопроса")
} }
} else { } else {
throw new Error("Не передан тип вопроса") throw new Error("Не передан id вопроса")
} }
} else {
throw new Error("Не передан id вопроса")
} }
} })()
})() }
} }
}, []) }, [open, originalImageUrl, editedUrlImagesList, questionId, questionType])
const closeModal = () => { const closeModal = () => {
setOriginalImageUrl("");
setEditedImages(null);
selfClose()
selfClose?.()
} }
const handleCropModalDeleteImageClick = () => { const handleCropModalDeleteImageClick = () => {
//сохранить пустую строку и дефолтные настройки картинки в самом вопросе, не информируя БД о удалении картинки //сохранить пустую строку и дефолтные настройки картинки в самом вопросе, не информируя БД о удалении картинки
selfClose?.() closeModal()
}; };
const saveImagesAndRules = async (blob?: Blob) => { const saveImagesAndRules = async (blob?: Blob) => {
setPictureUploading(true)
const img = document.createElement("img"); const img = document.createElement("img");
img.src = editedImages.mobile.url img.src = editedImages.mobile.url
const bloba = await getModifiedImageBlob(img, editedImages.mobile.newRules.crop, editedImages.mobile.newRules.darken) const bloba = await getModifiedImageBlob(img, editedImages.mobile.newRules.crop, editedImages.mobile.newRules.darken)
@ -113,6 +145,8 @@ export const CropModalInit: FC<CropOnOpenType> = ({
anchor.setAttribute("download", "ЖОПА"); anchor.setAttribute("download", "ЖОПА");
anchor.href = blobUrl; anchor.href = blobUrl;
anchor.click(); anchor.click();
closeModal()
setTimeout(() => setPictureUploading(false), 1000)
// if (!selectedVariantId) return; // if (!selectedVariantId) return;
// uploadQuestionImage(questionId, quizId, imageBlob, (question, url) => { // uploadQuestionImage(questionId, quizId, imageBlob, (question, url) => {
@ -127,6 +161,13 @@ export const CropModalInit: FC<CropOnOpenType> = ({
// }); // });
}; };
console.log("acceptedOriginalImageUrl")
console.log("workSpaceTypesList")
console.log("editedImages")
console.log(acceptedOriginalImageUrl)
console.log(workSpaceTypesList)
console.log(editedImages)
if (acceptedOriginalImageUrl.length === 0) return <></> if (acceptedOriginalImageUrl.length === 0) return <></>
if (workSpaceTypesList[questionType] === undefined) return <></> if (workSpaceTypesList[questionType] === undefined) return <></>
if (editedImages === null) return <></> if (editedImages === null) return <></>
@ -134,6 +175,7 @@ export const CropModalInit: FC<CropOnOpenType> = ({
return ( return (
<> <>
<CropModal <CropModal
open={open}
editedImages={editedImages} editedImages={editedImages}
workSpaceTypes={workSpaceTypesList[questionType]} workSpaceTypes={workSpaceTypesList[questionType]}
originalImageUrl={acceptedOriginalImageUrl} originalImageUrl={acceptedOriginalImageUrl}
@ -151,4 +193,20 @@ export const CropModalInit: FC<CropOnOpenType> = ({
</> </>
) )
}; };
// function handleCropModalSaveClick(imageBlob: Blob) { OptionsPicture
// if (!selectedVariantId) return;
// uploadQuestionImage(question.id, quizQid, imageBlob, (question, url) => {
// if (!("variants" in question.content)) return;
// const variant = question.content.variants.find(
// (variant) => variant.id === selectedVariantId,
// );
// if (!variant) return;
// variant.extendedText = url;
// });
// }