держится контекст о выбранной картинке у Images
Some checks failed
Deploy / CreateImage (push) Failing after 3m49s
Deploy / DeployService (push) Failing after 25s

This commit is contained in:
Nastya 2025-06-20 20:07:46 +03:00
parent 9f32bd9c9d
commit 38bd30ce35
3 changed files with 54 additions and 50 deletions

@ -10,7 +10,8 @@ import UploadIcon from "@/assets/icons/UploadIcon";
import { sendFile } from "@/api/quizRelase"; import { sendFile } from "@/api/quizRelase";
import { ACCEPT_SEND_FILE_TYPES_MAP, MAX_FILE_SIZE } from "../../tools/fileUpload"; import { ACCEPT_SEND_FILE_TYPES_MAP, MAX_FILE_SIZE } from "../../tools/fileUpload";
type OwnImageProps = { // Пропсы компонента
export type OwnImageProps = {
imageUrl?: string; imageUrl?: string;
questionId: string; questionId: string;
variantId: string; variantId: string;
@ -21,24 +22,24 @@ export const OwnImage = ({ imageUrl, questionId, variantId, onValidationError }:
const theme = useTheme(); const theme = useTheme();
const { t } = useTranslation(); const { t } = useTranslation();
const { quizId, preview } = useQuizStore(); const { quizId, preview } = useQuizStore();
const { answers, updateAnswer, ownVariants, updateOwnVariant } = useQuizViewStore((state) => state); const { ownVariants, updateOwnVariant } = useQuizViewStore((state) => state);
const { enqueueSnackbar } = useSnackbar(); const { enqueueSnackbar } = useSnackbar();
const [selectedFile, setSelectedFile] = useState<File | null>(null); const [selectedFile, setSelectedFile] = useState<File | null>(null);
const [isUploading, setIsUploading] = useState(false); const [isUploading, setIsUploading] = useState(false);
const fileInputRef = useRef<HTMLInputElement>(null); const fileInputRef = useRef<HTMLInputElement>(null);
// Получаем ownVariant для этого варианта
const ownVariantData = ownVariants.find((v) => v.id === variantId); const ownVariantData = ownVariants.find((v) => v.id === variantId);
// Загрузка файла
const uploadImage = async (file: File) => { const uploadImage = async (file: File) => {
if (isUploading) return; if (isUploading) return;
if (!file) return; if (!file) return;
if (file.size > MAX_FILE_SIZE) { if (file.size > MAX_FILE_SIZE) {
onValidationError("size"); onValidationError("size");
return; return;
} }
const isFileTypeAccepted = ACCEPT_SEND_FILE_TYPES_MAP.picture.some((fileType) => const isFileTypeAccepted = ACCEPT_SEND_FILE_TYPES_MAP.picture.some((fileType) =>
file.name.toLowerCase().endsWith(fileType) file.name.toLowerCase().endsWith(fileType)
); );
@ -46,28 +47,16 @@ export const OwnImage = ({ imageUrl, questionId, variantId, onValidationError }:
onValidationError("type"); onValidationError("type");
return; return;
} }
setIsUploading(true); setIsUploading(true);
try { try {
const data = await sendFile({ const data = await sendFile({
questionId, questionId,
body: { body: { file, name: file.name, preview },
file: file,
name: file.name,
preview,
},
qid: quizId, qid: quizId,
}); });
const fileId = data?.data.fileIDMap[questionId];
const fileId = data!.data.fileIDMap[questionId];
// Сохраняем fileId в originalImageUrl
updateOwnVariant(variantId, "", "", fileId);
// Для UI — локальный preview
const localImageUrl = URL.createObjectURL(file); const localImageUrl = URL.createObjectURL(file);
updateAnswer(questionId, `${file.name}|${localImageUrl}`, 0); updateOwnVariant(variantId, "", "", fileId, localImageUrl);
setSelectedFile(file); setSelectedFile(file);
} catch (error) { } catch (error) {
console.error("Error uploading image:", error); console.error("Error uploading image:", error);
@ -77,6 +66,7 @@ export const OwnImage = ({ imageUrl, questionId, variantId, onValidationError }:
} }
}; };
// Обработчик выбора файла
const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => { const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0]; const file = event.target.files?.[0];
if (file) { if (file) {
@ -84,24 +74,29 @@ export const OwnImage = ({ imageUrl, questionId, variantId, onValidationError }:
} }
}; };
// Открытие диалога выбора файла
const handleClick = (e: React.MouseEvent) => { const handleClick = (e: React.MouseEvent) => {
e.stopPropagation(); e.stopPropagation();
if (fileInputRef.current) { if (fileInputRef.current) fileInputRef.current.value = "";
fileInputRef.current.value = "";
}
fileInputRef.current?.click(); fileInputRef.current?.click();
}; };
// Удаление изображения
const handleRemoveImage = (e: React.MouseEvent) => { const handleRemoveImage = (e: React.MouseEvent) => {
e.stopPropagation(); e.stopPropagation();
setSelectedFile(null); setSelectedFile(null);
updateAnswer(questionId, "", 0); updateOwnVariant(variantId, "", "", "", "");
updateOwnVariant(variantId, "", "", "");
}; };
const imageToDisplay = selectedFile // Определяем, что показывать
? URL.createObjectURL(selectedFile) let imageToDisplay: string | null = null;
: ownVariantData?.variant.originalImageUrl || imageUrl; if (selectedFile) {
imageToDisplay = URL.createObjectURL(selectedFile);
} else if (ownVariantData?.variant.localImageUrl) {
imageToDisplay = ownVariantData.variant.localImageUrl;
} else if (imageUrl) {
imageToDisplay = imageUrl;
}
if (isUploading) { if (isUploading) {
return ( return (
@ -137,7 +132,6 @@ export const OwnImage = ({ imageUrl, questionId, variantId, onValidationError }:
accept={ACCEPT_SEND_FILE_TYPES_MAP.picture.join(",")} accept={ACCEPT_SEND_FILE_TYPES_MAP.picture.join(",")}
hidden hidden
/> />
{imageToDisplay ? ( {imageToDisplay ? (
<> <>
<Box sx={{ width: "100%", height: "100%", position: "relative" }}> <Box sx={{ width: "100%", height: "100%", position: "relative" }}>
@ -147,26 +141,24 @@ export const OwnImage = ({ imageUrl, questionId, variantId, onValidationError }:
style={{ width: "100%", height: "100%", objectFit: "cover" }} style={{ width: "100%", height: "100%", objectFit: "cover" }}
/> />
</Box> </Box>
{(selectedFile || ownVariantData?.variant.originalImageUrl) && ( <IconButton
<IconButton onClick={handleRemoveImage}
onClick={handleRemoveImage} sx={{
sx={{ position: "absolute",
position: "absolute", top: 8,
top: 8, right: 8,
right: 8, zIndex: 1,
zIndex: 1, backgroundColor: "rgba(0, 0, 0, 0.5)",
backgroundColor: "rgba(0, 0, 0, 0.5)", color: "white",
color: "white", height: "25px",
height: "25px", width: "25px",
width: "25px", "&:hover": {
"&:hover": { backgroundColor: "rgba(0, 0, 0, 0.7)",
backgroundColor: "rgba(0, 0, 0, 0.7)", },
}, }}
}} >
> <CloseIcon />
<CloseIcon /> </IconButton>
</IconButton>
)}
</> </>
) : ( ) : (
<Box <Box

@ -51,6 +51,8 @@ export type QuestionVariant = {
isMulti?: boolean; isMulti?: boolean;
/** Оригинал изображения (до кропа) */ /** Оригинал изображения (до кропа) */
originalImageUrl: string; originalImageUrl: string;
/** Локальный URL для предпросмотра */
localImageUrl?: string;
points?: number; points?: number;
}; };
export interface QuestionVariantWithEditedImages extends QuestionVariant { export interface QuestionVariantWithEditedImages extends QuestionVariant {

@ -30,7 +30,13 @@ interface QuizViewStore {
interface QuizViewActions { interface QuizViewActions {
updateAnswer: (questionId: string, answer: string | string[] | Moment, points: number) => void; updateAnswer: (questionId: string, answer: string | string[] | Moment, points: number) => void;
deleteAnswer: (questionId: string) => void; deleteAnswer: (questionId: string) => void;
updateOwnVariant: (id: string, answer: string, extendedText?: string, originalImageUrl?: string) => void; updateOwnVariant: (
id: string,
answer: string,
extendedText?: string,
originalImageUrl?: string,
localImageUrl?: string
) => void;
deleteOwnVariant: (id: string) => void; deleteOwnVariant: (id: string) => void;
setCurrentQuizStep: (step: QuizStep) => void; setCurrentQuizStep: (step: QuizStep) => void;
} }
@ -90,7 +96,7 @@ export const createQuizViewStore = () =>
} }
); );
}, },
updateOwnVariant(id, answer, extendedText, originalImageUrl) { updateOwnVariant(id, answer, extendedText, originalImageUrl, localImageUrl) {
set( set(
(state) => { (state) => {
const index = state.ownVariants.findIndex((variant) => variant.id === id); const index = state.ownVariants.findIndex((variant) => variant.id === id);
@ -104,6 +110,7 @@ export const createQuizViewStore = () =>
extendedText: extendedText || "", extendedText: extendedText || "",
hints: "", hints: "",
originalImageUrl: originalImageUrl || "", originalImageUrl: originalImageUrl || "",
localImageUrl: localImageUrl || "",
}, },
}); });
} else { } else {
@ -114,6 +121,9 @@ export const createQuizViewStore = () =>
if (originalImageUrl) { if (originalImageUrl) {
state.ownVariants[index].variant.originalImageUrl = originalImageUrl; state.ownVariants[index].variant.originalImageUrl = originalImageUrl;
} }
if (localImageUrl) {
state.ownVariants[index].variant.localImageUrl = localImageUrl;
}
} }
}, },
false, false,