frontAnswerer/lib/components/ViewPublicationPage/questions/File/UploadFile.tsx
2024-05-31 19:41:18 +03:00

146 lines
4.8 KiB
TypeScript

import { useState } from "react";
import { Box, ButtonBase, Skeleton, Typography, useTheme } from "@mui/material";
import { enqueueSnackbar } from "notistack";
import { sendAnswer, sendFile } from "@api/quizRelase";
import { useQuizData } from "@contexts/QuizDataContext";
import { useRootContainerSize } from "@contexts/RootContainerWidthContext";
import { useQuizViewStore } from "@stores/quizView";
import {
ACCEPT_SEND_FILE_TYPES_MAP,
MAX_FILE_SIZE,
UPLOAD_FILE_DESCRIPTIONS_MAP,
} from "@/components/ViewPublicationPage/tools/fileUpload";
import Info from "@icons/Info";
import UploadIcon from "@icons/UploadIcon";
import type { QuizQuestionFile } from "@model/questionTypes/file";
import type { ModalWarningType } from "./index";
type UploadFileProps = {
currentQuestion: QuizQuestionFile;
setModalWarningType: (modalType: ModalWarningType) => void;
isSending: boolean;
setIsSending: (isSending: boolean) => void;
};
export const UploadFile = ({ currentQuestion, setModalWarningType, isSending, setIsSending }: UploadFileProps) => {
const { quizId, preview } = useQuizData();
const [isDropzoneHighlighted, setIsDropzoneHighlighted] = useState<boolean>(false);
const theme = useTheme();
const answers = useQuizViewStore((state) => state.answers);
const { updateAnswer } = useQuizViewStore((state) => state);
const isMobile = useRootContainerSize() < 500;
const answer = answers.find(({ questionId }) => questionId === currentQuestion.id)?.answer as string;
const uploadFile = async (file: File | undefined) => {
if (isSending) return;
if (!file) return;
if (file.size > MAX_FILE_SIZE) return setModalWarningType("errorSize");
const isFileTypeAccepted = ACCEPT_SEND_FILE_TYPES_MAP[currentQuestion.content.type].some((fileType) =>
file.name.toLowerCase().endsWith(fileType)
);
if (!isFileTypeAccepted) return setModalWarningType("errorType");
setIsSending(true);
try {
const data = await sendFile({
questionId: currentQuestion.id,
body: {
file: file,
name: file.name,
preview,
},
qid: quizId,
});
await sendAnswer({
questionId: currentQuestion.id,
body: `https://storage.yandexcloud.net/squizanswer/${quizId}/${
currentQuestion.id
}/${data!.data.fileIDMap[currentQuestion.id]}`,
qid: quizId,
preview,
});
updateAnswer(currentQuestion.id, `${file.name}|${URL.createObjectURL(file)}`, 0);
} catch (error) {
console.error(error);
enqueueSnackbar("ответ не был засчитан");
}
setIsSending(false);
};
const onDrop = (event: React.DragEvent<HTMLDivElement>) => {
event.preventDefault();
setIsDropzoneHighlighted(false);
const file = event.dataTransfer.files[0];
uploadFile(file);
};
return (
<Box sx={{ display: "flex", alignItems: "center" }}>
{isSending ? (
<Skeleton variant="rounded" sx={{ width: "100%", height: "120px", maxWidth: "560px" }} />
) : (
<ButtonBase component="label" sx={{ justifyContent: "flex-start", width: "100%" }}>
<input
onChange={({ target }) => uploadFile(target.files?.[0])}
hidden
accept={ACCEPT_SEND_FILE_TYPES_MAP[currentQuestion.content.type].join(",")}
multiple
type="file"
/>
<Box
onDragEnter={() => !answer?.split("|")[0] && setIsDropzoneHighlighted(true)}
onDragLeave={() => setIsDropzoneHighlighted(false)}
onDragOver={(event) => event.preventDefault()}
onDrop={onDrop}
sx={{
width: "100%",
height: isMobile ? undefined : "120px",
display: "flex",
gap: "50px",
justifyContent: "flex-start",
alignItems: "center",
padding: "33px 44px 33px 55px",
backgroundColor: "#F2F3F7",
border: `1px solid ${isDropzoneHighlighted ? "red" : "#9A9AAF"}`,
borderRadius: "8px",
}}
>
<UploadIcon />
<Box>
<Typography sx={{ color: "#9A9AAF", fontWeight: 500 }}>
{UPLOAD_FILE_DESCRIPTIONS_MAP[currentQuestion.content.type].title}
</Typography>
<Typography
sx={{
color: "#9A9AAF",
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={() => setModalWarningType(currentQuestion.content.type)}
/>
</Box>
);
};