frontAnswerer/lib/components/ViewPublicationPage/questions/File.tsx

342 lines
13 KiB
TypeScript
Raw Normal View History

2023-12-16 14:55:56 +00:00
import {
2024-02-02 14:35:02 +00:00
Box,
ButtonBase,
IconButton,
Modal,
Typography,
useTheme
2023-12-16 14:55:56 +00:00
} from "@mui/material";
import { updateAnswer, useQuizViewStore } from "@stores/quizView";
2023-12-16 14:55:56 +00:00
import CloseBold from "@icons/CloseBold";
import UploadIcon from "@icons/UploadIcon";
2023-12-16 14:55:56 +00:00
2024-01-23 18:00:06 +00:00
import { sendAnswer, sendFile } from "@api/quizRelase";
import Info from "@icons/Info";
import type { UploadFileType } from "@model/questionTypes/file";
import { enqueueSnackbar } from "notistack";
import type { DragEvent } from "react";
import { useState, type ChangeEvent } from "react";
import { useRootContainerSize } from "../../../contexts/RootContainerWidthContext";
import type { QuizQuestionFile } from "../../../model/questionTypes/file";
import { useQuizData } from "@contexts/QuizDataContext";
2023-12-16 14:55:56 +00:00
type FileProps = {
2024-02-02 14:35:02 +00:00
currentQuestion: QuizQuestionFile;
2023-12-16 14:55:56 +00:00
};
2024-02-02 14:35:02 +00:00
const CurrentModal = ({ status }: { status: "errorType" | "errorSize" | "picture" | "video" | "audio" | "document" | ""; }) => {
switch (status) {
case 'errorType':
return (<>
<Typography>Выбран некорректный тип файла</Typography>
</>);
case 'errorSize':
return (<>
<Typography>Файл слишком большой. Максимальный размер 50 МБ</Typography>
</>);
default:
return (<>
<Typography>Допустимые расширения файлов:</Typography>
<Typography>{
//@ts-ignore
ACCEPT_SEND_FILE_TYPES_MAP[status].join(" ")}</Typography>
</>);
}
};
const ACCEPT_SEND_FILE_TYPES_MAP = {
2024-02-02 14:35:02 +00:00
picture: [
".jpeg",
".jpg",
".png",
".ico",
".gif",
".tiff",
".webp",
".eps",
".svg"
],
video: [
".mp4",
".mov",
".wmv",
".avi",
".avchd",
".flv",
".f4v",
".swf",
".mkv",
".webm",
".mpeg-2"
],
audio: [
".aac",
".aiff",
".dsd",
".flac",
".mp3",
".mqa",
".ogg",
".wav",
".wma"
],
document: [
".doc",
".docx",
".dotx",
".rtf",
".odt",
".pdf",
".txt",
".xls",
".ppt",
".xlsx",
".pptx",
".pages",
],
2024-02-02 14:35:02 +00:00
};
const UPLOAD_FILE_DESCRIPTIONS_MAP: Record<
2024-02-02 14:35:02 +00:00
UploadFileType,
{ title: string; description: string; }
2023-12-16 14:55:56 +00:00
> = {
2024-02-02 14:35:02 +00:00
picture: {
title: "Добавить изображение",
description: "Принимает изображения",
},
video: {
title: "Добавить видео",
description: "Принимает .mp4 и .mov формат — максимум 50мб",
2024-02-02 14:35:02 +00:00
},
audio: { title: "Добавить аудиофайл", description: "Принимает аудиофайлы" },
document: { title: "Добавить документ", description: "Принимает документы" },
2023-12-16 14:55:56 +00:00
} as const;
export const File = ({ currentQuestion }: FileProps) => {
2024-02-02 14:35:02 +00:00
const theme = useTheme();
const { answers } = useQuizViewStore();
const quizId = useQuizData();
2024-02-02 14:35:02 +00:00
const [statusModal, setStatusModal] = useState<"errorType" | "errorSize" | "picture" | "video" | "audio" | "document" | "">("");
2024-02-02 14:35:02 +00:00
const answer = answers.find(
({ questionId }) => questionId === currentQuestion.id
)?.answer as string;
const isMobile = useRootContainerSize() < 500;
2024-02-02 14:35:02 +00:00
const uploadFile = async ({ target }: ChangeEvent<HTMLInputElement>) => {
const file = target.files?.[0];
if (file) {
if (file.size <= 52428800) {
//проверяем на соответствие
console.log(file.name.toLowerCase());
if (ACCEPT_SEND_FILE_TYPES_MAP[currentQuestion.content.type].find((ednding => {
console.log(ednding);
console.log(file.name.toLowerCase().endsWith(ednding));
return file.name.toLowerCase().endsWith(ednding);
}))) {
2024-02-02 14:35:02 +00:00
//Нужный формат
console.log(file);
try {
2024-02-02 14:35:02 +00:00
const data = await sendFile({
questionId: currentQuestion.id,
body: {
file: file,
name: file.name
},
qid: quizId,
2024-02-02 14:35:02 +00:00
});
console.log(data);
2024-02-02 14:35:02 +00:00
await sendAnswer({
questionId: currentQuestion.id,
body: `https://storage.yandexcloud.net/squizanswer/${quizId}/${currentQuestion.id}/${data.data.fileIDMap[currentQuestion.id]}`,
qid: quizId,
2024-02-02 14:35:02 +00:00
});
2024-02-02 14:35:02 +00:00
updateAnswer(
currentQuestion.id,
`${file.name}|${URL.createObjectURL(file)}`,
0
2024-02-02 14:35:02 +00:00
);
2024-02-02 14:35:02 +00:00
} catch (e) {
console.log(e);
enqueueSnackbar("ответ не был засчитан");
}
2024-02-02 14:35:02 +00:00
} else {
2024-02-02 14:35:02 +00:00
//неподходящий формат
setStatusModal("errorType");
}
} else {
2024-02-02 14:35:02 +00:00
setStatusModal("errorSize");
}
2023-12-16 14:55:56 +00:00
2024-02-02 14:35:02 +00:00
}
};
2024-02-02 14:35:02 +00:00
return (
<>
<Box>
<Typography variant="h5" color={theme.palette.text.primary} sx={{wordBreak: "break-word"}}>{currentQuestion.title}</Typography>
<Box
2024-02-02 14:35:02 +00:00
sx={{
display: "flex",
flexDirection: "column",
width: "100%",
marginTop: "20px",
maxWidth: answer?.split("|")[0] ? "640px" : "600px",
}}
2023-12-16 14:55:56 +00:00
>
2024-02-02 14:35:02 +00:00
{answer?.split("|")[0] && (
<Box sx={{ display: "flex", alignItems: "center", gap: "15px" }}>
<Typography color={theme.palette.text.primary}>Вы загрузили:</Typography>
<Box
sx={{
padding: "5px 5px 5px 16px",
backgroundColor: theme.palette.primary.main,
borderRadius: "8px",
color: "#FFFFFF",
display: "flex",
alignItems: "center",
overflow: "hidden",
gap: "15px",
}}
>
<Typography
sx={{
whiteSpace: "nowrap",
textOverflow: "ellipsis",
overflow: "hidden",
}}
>
{answer?.split("|")[0]}</Typography>
<IconButton
sx={{ p: 0 }}
onClick={() => {
updateAnswer(currentQuestion.id, "", 0);
2024-02-02 14:35:02 +00:00
}}
>
<CloseBold />
</IconButton>
</Box>
</Box>
)}
{!answer?.split("|")[0] && (
<Box sx={{
display: "flex",
alignItems: "center"
}}>
<ButtonBase component="label" sx={{ justifyContent: "flex-start", width: "100%" }}>
<input
onChange={uploadFile}
hidden
accept={ACCEPT_SEND_FILE_TYPES_MAP[currentQuestion.content.type].join(",")}
multiple
type="file"
/>
<Box
onDragOver={(event: DragEvent<HTMLDivElement>) =>
event.preventDefault()
}
sx={{
width: "100%",
height: isMobile ? undefined : "120px",
display: "flex",
gap: "50px",
justifyContent: "flex-start",
alignItems: "center",
padding: "33px 44px 33px 55px",
backgroundColor: theme.palette.background.default,
border: `1px solid #9A9AAF`,
// border: `1px solid ${theme.palette.grey2.main}`,
borderRadius: "8px",
}}
>
<UploadIcon />
<Box>
<Typography
sx={{
color: "#9A9AAF",
// color: theme.palette.grey2.main,
fontWeight: 500,
}}
>
{
UPLOAD_FILE_DESCRIPTIONS_MAP[currentQuestion.content.type]
.title
}
</Typography>
<Typography
sx={{
color: "#9A9AAF",
// color: theme.palette.grey2.main,
fontSize: "16px",
lineHeight: "19px",
}}
>
{
UPLOAD_FILE_DESCRIPTIONS_MAP[currentQuestion.content.type]
.description
}
</Typography>
</Box>
</Box>
</ButtonBase>
<Info sx={{ width: "40px", height: "40px" }} color={theme.palette.primary.main} onClick={() => setStatusModal(currentQuestion.content.type)} />
</Box>
)}
{answer && currentQuestion.content.type === "picture" && (
<img
src={answer.split("|")[1]}
alt=""
style={{
marginTop: "15px",
maxWidth: "300px",
maxHeight: "300px",
}}
/>
)}
{answer && currentQuestion.content.type === "video" && (
<video
src={answer.split("|")[1]}
style={{
marginTop: "15px",
maxWidth: "300px",
maxHeight: "300px",
objectFit: "cover",
}}
/>
)}
</Box>
2023-12-16 14:55:56 +00:00
</Box>
2024-02-02 14:35:02 +00:00
<Modal
open={Boolean(statusModal)}
onClose={() => setStatusModal("")}
>
<Box sx={{
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: isMobile ? 300 : 400,
bgcolor: 'background.paper',
borderRadius: 3,
boxShadow: 24,
p: 4,
}}>
<CurrentModal status={statusModal} />
</Box>
</Modal>
</>
);
2023-12-29 00:58:19 +00:00
2023-12-16 14:55:56 +00:00
};