корректная отправка ответа
All checks were successful
Deploy / CreateImage (push) Successful in 4m30s
Deploy / DeployService (push) Successful in 25s

This commit is contained in:
Nastya 2025-06-20 22:22:18 +03:00
parent b8b30a352b
commit 6a1f015ff8
5 changed files with 75 additions and 42 deletions

@ -1,5 +1,10 @@
import React, { forwardRef } from "react"; import React, { forwardRef, useState } from "react";
import { useQuizViewStore } from "@stores/quizView"; import { useQuizViewStore } from "@stores/quizView";
import { useQuizStore } from "@/stores/useQuizStore";
import { useSnackbar } from "notistack";
import { useTranslation } from "react-i18next";
import { sendFile } from "@/api/quizRelase";
import { ACCEPT_SEND_FILE_TYPES_MAP, MAX_FILE_SIZE } from "../../tools/fileUpload";
interface OwnVarimgImageProps { interface OwnVarimgImageProps {
questionId: string; questionId: string;
@ -7,14 +12,58 @@ interface OwnVarimgImageProps {
} }
export const OwnVarimgImage = forwardRef<HTMLInputElement, OwnVarimgImageProps>(({ questionId, variantId }, ref) => { export const OwnVarimgImage = forwardRef<HTMLInputElement, OwnVarimgImageProps>(({ questionId, variantId }, ref) => {
const { updateAnswer, updateOwnVariantWithFile } = useQuizViewStore((state) => state); const { updateAnswer, updateOwnVariant } = useQuizViewStore((state) => state);
const { quizId, preview } = useQuizStore();
const { enqueueSnackbar } = useSnackbar();
const { t } = useTranslation();
const [isUploading, setIsUploading] = useState(false);
const uploadImage = async (file: File) => {
if (isUploading) return;
if (!file) return;
// Валидация размера файла
if (file.size > MAX_FILE_SIZE) {
enqueueSnackbar(t("file is too big"), { variant: "warning" });
return;
}
// Валидация типа файла
const isFileTypeAccepted = ACCEPT_SEND_FILE_TYPES_MAP.picture.some((fileType) =>
file.name.toLowerCase().endsWith(fileType)
);
if (!isFileTypeAccepted) {
enqueueSnackbar(t("file type is not supported"), { variant: "warning" });
return;
}
setIsUploading(true);
try {
const data = await sendFile({
questionId,
body: { file, name: file.name, preview },
qid: quizId,
});
const fileId = data?.data.fileIDMap[questionId];
const localImageUrl = URL.createObjectURL(file);
updateOwnVariant(variantId, "", "", fileId, localImageUrl);
// Автоматически выбираем "own" вариант при загрузке файла
updateAnswer(questionId, variantId, 0);
} catch (error) {
console.error("Error uploading image:", error);
enqueueSnackbar(t("The answer was not counted"));
} finally {
setIsUploading(false);
}
};
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) {
// @ts-ignore uploadImage(file);
updateOwnVariantWithFile(variantId, file);
updateAnswer(questionId, variantId, 0);
event.target.value = ""; event.target.value = "";
} }
}; };
@ -24,8 +73,9 @@ export const OwnVarimgImage = forwardRef<HTMLInputElement, OwnVarimgImageProps>(
type="file" type="file"
ref={ref} ref={ref}
style={{ display: "none" }} style={{ display: "none" }}
accept="image/*" accept={ACCEPT_SEND_FILE_TYPES_MAP.picture.join(",")}
onChange={handleFileChange} onChange={handleFileChange}
disabled={isUploading}
/> />
); );
}); });

@ -37,9 +37,7 @@ export const Varimg = ({ currentQuestion }: VarimgProps) => {
); );
const ownVariantData = ownVariants.find((v) => v.id === answer); const ownVariantData = ownVariants.find((v) => v.id === answer);
const ownImageUrl = useMemo(() => { const ownImageUrl = useMemo(() => {
return ownVariantData?.variant.file return ownVariantData?.variant.localImageUrl;
? URL.createObjectURL(ownVariantData.variant.file)
: ownVariantData?.variant.localImageUrl;
}, [ownVariantData]); }, [ownVariantData]);
const inputRef = useRef<HTMLInputElement>(null); const inputRef = useRef<HTMLInputElement>(null);

@ -54,7 +54,7 @@ export type QuestionVariant = {
/** Локальный URL для предпросмотра */ /** Локальный URL для предпросмотра */
localImageUrl?: string; localImageUrl?: string;
points?: number; points?: number;
file?: File; fileId?: string;
}; };
export interface QuestionVariantWithEditedImages extends QuestionVariant { export interface QuestionVariantWithEditedImages extends QuestionVariant {
editedUrlImagesList?: EditedUrlImagesList | null; editedUrlImagesList?: EditedUrlImagesList | null;

@ -37,7 +37,6 @@ interface QuizViewActions {
originalImageUrl?: string, originalImageUrl?: string,
localImageUrl?: string localImageUrl?: string
) => void; ) => void;
updateOwnVariantWithFile: (variantId: string, file: File) => void;
deleteOwnVariant: (id: string) => void; deleteOwnVariant: (id: string) => void;
setCurrentQuizStep: (step: QuizStep) => void; setCurrentQuizStep: (step: QuizStep) => void;
} }
@ -135,35 +134,6 @@ export const createQuizViewStore = () =>
} }
); );
}, },
updateOwnVariantWithFile(variantId, file) {
set(
(state) => {
const index = state.ownVariants.findIndex((v) => v.id === variantId);
if (index < 0) {
state.ownVariants.push({
id: variantId,
variant: {
id: variantId,
answer: "",
extendedText: "",
hints: "",
originalImageUrl: "",
file: file,
},
});
} else {
state.ownVariants[index].variant.file = file;
state.ownVariants[index].variant.localImageUrl = undefined;
}
},
false,
{
type: "updateOwnVariantWithFile",
variantId,
}
);
},
deleteOwnVariant(id) { deleteOwnVariant(id) {
set( set(
(state) => { (state) => {

@ -267,9 +267,24 @@ export async function sendQuestionAnswer(
ownVariants[ownVariants.findIndex((variant) => variant.id === questionAnswer.answer)]?.variant?.answer || ""; ownVariants[ownVariants.findIndex((variant) => variant.id === questionAnswer.answer)]?.variant?.answer || "";
if (!variant) throw new Error(`Cannot find variant with id ${questionAnswer.answer} in question ${question.id}`); if (!variant) throw new Error(`Cannot find variant with id ${questionAnswer.answer} in question ${question.id}`);
let imageValue = variant.extendedText;
if (variant.isOwn) {
// Берем fileId из ownVariants для own вариантов
const ownVariantData = ownVariants.find((v) => v.id === variant.id)?.variant;
if (ownVariantData?.originalImageUrl) {
// Конструируем полный URL для own вариантов
const baseUrl =
"https://s3.timeweb.cloud/3c580be9-cf31f296-d055-49cf-b39e-30c7959dc17b/squizimages/55c25eb9-4533-4d51-9da5-54e63e8aeace/";
// Убираем расширение файла из fileId
const fileIdWithoutExtension = ownVariantData.originalImageUrl.replace(/\.(jpg|jpeg|png|gif|webp)$/i, "");
imageValue = baseUrl + fileIdWithoutExtension;
}
}
const body = { const body = {
Image: variant.extendedText, Image: imageValue,
Description: question.content.own ? ownAnswer : variant.answer, Description: variant.isOwn ? ownAnswer : variant.answer,
}; };
if (!body) throw new Error(`Body of answer in question ${question.id} is undefined`); if (!body) throw new Error(`Body of answer in question ${question.id} is undefined`);