163 lines
5.1 KiB
TypeScript
163 lines
5.1 KiB
TypeScript
import { useState, Dispatch, SetStateAction } from "react";
|
|
import { Box, ButtonBase, Skeleton, Typography, useTheme } from "@mui/material";
|
|
import { enqueueSnackbar } from "notistack";
|
|
|
|
import { sendAnswer, sendFile } from "@api/quizRelase";
|
|
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 { useQuizStore } from "@/stores/useQuizStore";
|
|
import { useTranslation } from "react-i18next";
|
|
|
|
export type ModalWarningType = "errorType" | "errorSize" | "picture" | "video" | "audio" | "document" | null;
|
|
|
|
type UploadFileProps = {
|
|
currentQuestion: QuizQuestionFile;
|
|
setModalWarningType: Dispatch<SetStateAction<ModalWarningType>>;
|
|
isSending: boolean;
|
|
setIsSending: Dispatch<SetStateAction<boolean>>;
|
|
onFileUpload: (file: File) => Promise<void>;
|
|
isUploading: boolean;
|
|
};
|
|
|
|
export const UploadFile = ({
|
|
currentQuestion,
|
|
setModalWarningType,
|
|
isSending,
|
|
setIsSending,
|
|
onFileUpload,
|
|
isUploading,
|
|
}: UploadFileProps) => {
|
|
const { quizId, preview } = useQuizStore();
|
|
const [isDropzoneHighlighted, setIsDropzoneHighlighted] = useState<boolean>(false);
|
|
const theme = useTheme();
|
|
const { t } = useTranslation();
|
|
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 handleFileChange = async (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
const file = event.target.files?.[0];
|
|
if (!file) return;
|
|
|
|
const fileType = file.type.split("/")[0];
|
|
const fileExtension = file.name.split(".").pop()?.toLowerCase();
|
|
|
|
if (!ACCEPT_SEND_FILE_TYPES_MAP[currentQuestion.content.type].includes(`.${fileExtension}`)) {
|
|
setModalWarningType("errorType");
|
|
return;
|
|
}
|
|
|
|
if (file.size > 50 * 1024 * 1024) {
|
|
setModalWarningType("errorSize");
|
|
return;
|
|
}
|
|
|
|
setIsSending(true);
|
|
try {
|
|
await onFileUpload(file);
|
|
} finally {
|
|
setIsSending(false);
|
|
}
|
|
};
|
|
|
|
const onDrop = async (event: React.DragEvent<HTMLLabelElement>) => {
|
|
event.preventDefault();
|
|
setIsDropzoneHighlighted(false);
|
|
|
|
const file = event.dataTransfer.files[0];
|
|
if (!file) return;
|
|
|
|
const fileType = file.type.split("/")[0];
|
|
const fileExtension = file.name.split(".").pop()?.toLowerCase();
|
|
|
|
if (!ACCEPT_SEND_FILE_TYPES_MAP[currentQuestion.content.type].includes(`.${fileExtension}`)) {
|
|
setModalWarningType("errorType");
|
|
return;
|
|
}
|
|
|
|
if (file.size > 50 * 1024 * 1024) {
|
|
setModalWarningType("errorSize");
|
|
return;
|
|
}
|
|
|
|
setIsSending(true);
|
|
try {
|
|
await onFileUpload(file);
|
|
} finally {
|
|
setIsSending(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Box sx={{ display: "flex", alignItems: "center" }}>
|
|
{isSending ? (
|
|
<Skeleton
|
|
variant="rounded"
|
|
sx={{ width: "100%", height: "120px", maxWidth: "560px" }}
|
|
/>
|
|
) : (
|
|
<Box
|
|
component="label"
|
|
sx={{
|
|
width: "100%",
|
|
height: "300px",
|
|
border: "2px dashed",
|
|
borderColor: isDropzoneHighlighted ? "primary.main" : "grey.300",
|
|
borderRadius: "12px",
|
|
display: "flex",
|
|
flexDirection: "column",
|
|
alignItems: "center",
|
|
justifyContent: "center",
|
|
cursor: "pointer",
|
|
transition: "all 0.2s",
|
|
backgroundColor: isDropzoneHighlighted ? "action.hover" : "background.paper",
|
|
opacity: isSending || isUploading ? 0.7 : 1,
|
|
pointerEvents: isSending || isUploading ? "none" : "auto",
|
|
"&:hover": {
|
|
borderColor: "primary.main",
|
|
backgroundColor: "action.hover",
|
|
},
|
|
}}
|
|
onDragEnter={() => setIsDropzoneHighlighted(true)}
|
|
onDragLeave={() => setIsDropzoneHighlighted(false)}
|
|
onDragOver={(event) => event.preventDefault()}
|
|
onDrop={onDrop}
|
|
>
|
|
<input
|
|
onChange={handleFileChange}
|
|
hidden
|
|
accept={ACCEPT_SEND_FILE_TYPES_MAP[currentQuestion.content.type].join(",")}
|
|
type="file"
|
|
/>
|
|
<UploadIcon color={isDropzoneHighlighted ? "primary" : "grey"} />
|
|
<Typography
|
|
variant="body1"
|
|
color={isDropzoneHighlighted ? "primary" : "text.secondary"}
|
|
sx={{ mt: 2 }}
|
|
>
|
|
{isUploading ? t("Uploading...") : t("Drop file here or click to upload")}
|
|
</Typography>
|
|
</Box>
|
|
)}
|
|
<Info
|
|
sx={{ width: "40px", height: "40px" }}
|
|
color={theme.palette.primary.main}
|
|
onClick={() => setModalWarningType(currentQuestion.content.type)}
|
|
/>
|
|
</Box>
|
|
);
|
|
};
|