diff --git a/lib/components/ViewPublicationPage/questions/File.tsx b/lib/components/ViewPublicationPage/questions/File.tsx
index 44ccffe..8865a8a 100644
--- a/lib/components/ViewPublicationPage/questions/File.tsx
+++ b/lib/components/ViewPublicationPage/questions/File.tsx
@@ -13,344 +13,243 @@ import CloseBold from "@icons/CloseBold";
import UploadIcon from "@icons/UploadIcon";
import { sendAnswer, sendFile } from "@api/quizRelase";
+import { useQuizData } from "@contexts/QuizDataContext";
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 { useState } from "react";
import { useRootContainerSize } from "../../../contexts/RootContainerWidthContext";
import type { QuizQuestionFile } from "../../../model/questionTypes/file";
-import { useQuizData } from "@contexts/QuizDataContext";
+import { ACCEPT_SEND_FILE_TYPES_MAP, MAX_FILE_SIZE, UPLOAD_FILE_DESCRIPTIONS_MAP } from "../tools/fileUpload";
+
+type ModalWarningType = "errorType" | "errorSize" | "picture" | "video" | "audio" | "document" | null;
type FileProps = {
currentQuestion: QuizQuestionFile;
};
-const CurrentModal = ({ status }: { status: "errorType" | "errorSize" | "picture" | "video" | "audio" | "document" | ""; }) => {
- switch (status) {
- case 'errorType':
- return (<>
- Выбран некорректный тип файла
- >);
- case 'errorSize':
- return (<>
- Файл слишком большой. Максимальный размер 50 МБ
- >);
- default:
- return (<>
- Допустимые расширения файлов:
- {
- //@ts-ignore
- ACCEPT_SEND_FILE_TYPES_MAP[status].join(" ")}
- >);
- }
-};
-
-const ACCEPT_SEND_FILE_TYPES_MAP = {
- 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",
- ],
-
-};
-
-
-const UPLOAD_FILE_DESCRIPTIONS_MAP: Record<
- UploadFileType,
- { title: string; description: string; }
-> = {
- picture: {
- title: "Добавить изображение",
- description: "Принимает изображения",
- },
- video: {
- title: "Добавить видео",
- description: "Принимает .mp4 и .mov формат — максимум 50мб",
- },
- audio: { title: "Добавить аудиофайл", description: "Принимает аудиофайлы" },
- document: { title: "Добавить документ", description: "Принимает документы" },
-} as const;
-
export const File = ({ currentQuestion }: FileProps) => {
const theme = useTheme();
const { answers } = useQuizViewStore();
const { quizId } = useQuizData();
- const [statusModal, setStatusModal] = useState<"errorType" | "errorSize" | "picture" | "video" | "audio" | "document" | "">("");
- const [readySend, setReadySend] = useState(true)
+ const [modalWarningType, setModalWarningType] = useState(null);
+ const [isSending, setIsSending] = useState(false);
+ const [isDropzoneHighlighted, setIsDropzoneHighlighted] = useState(false);
+ const isMobile = useRootContainerSize() < 500;
const answer = answers.find(
({ questionId }) => questionId === currentQuestion.id
)?.answer as string;
- const isMobile = useRootContainerSize() < 500;
- const uploadFile = async ({ target }: ChangeEvent) => {
- if (readySend) {
- setReadySend(false)
- 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);
- }))) {
- //Нужный формат
- console.log(file);
- try {
+ const uploadFile = async (file: File | undefined) => {
+ if (isSending) return;
+ if (!file) return;
+ if (file.size > MAX_FILE_SIZE) return setModalWarningType("errorSize");
- const data = await sendFile({
- questionId: currentQuestion.id,
- body: {
- file: file,
- name: file.name
- },
- qid: quizId,
- });
- console.log(data);
+ const isFileTypeAccepted = ACCEPT_SEND_FILE_TYPES_MAP[currentQuestion.content.type].some(
+ fileType => file.name.toLowerCase().endsWith(fileType)
+ );
- await sendAnswer({
- questionId: currentQuestion.id,
- body: `https://storage.yandexcloud.net/squizanswer/${quizId}/${currentQuestion.id}/${data.data.fileIDMap[currentQuestion.id]}`,
- qid: quizId,
- });
+ if (!isFileTypeAccepted) return setModalWarningType("errorType");
- updateAnswer(
- currentQuestion.id,
- `${file.name}|${URL.createObjectURL(file)}`,
- 0
- );
+ setIsSending(true);
+ try {
+ const data = await sendFile({
+ questionId: currentQuestion.id,
+ body: {
+ file: file,
+ name: file.name
+ },
+ qid: quizId,
+ });
+ console.log(data);
- } catch (e) {
- console.log(e);
- enqueueSnackbar("ответ не был засчитан");
- }
+ await sendAnswer({
+ questionId: currentQuestion.id,
+ body: `https://storage.yandexcloud.net/squizanswer/${quizId}/${currentQuestion.id}/${data.data.fileIDMap[currentQuestion.id]}`,
+ qid: quizId,
+ });
- } else {
-
- //неподходящий формат
- setStatusModal("errorType");
- }
- } else {
-
- setStatusModal("errorSize");
- }
-
- }
- setReadySend(true)
+ updateAnswer(currentQuestion.id, `${file.name}|${URL.createObjectURL(file)}`, 0);
+ } catch (e) {
+ console.log(e);
+ enqueueSnackbar("ответ не был засчитан");
}
+
+ setIsSending(false);
+ };
+
+ const onDrop = (event: React.DragEvent) => {
+ event.preventDefault();
+ setIsDropzoneHighlighted(false);
+
+ const file = event.dataTransfer.files[0];
+
+ uploadFile(file);
};
return (
- <>
-
- {currentQuestion.title}
-
- {answer?.split("|")[0] && (
-
- Вы загрузили:
-
+ {currentQuestion.title}
+
+ {answer?.split("|")[0] ? (
+
+ Вы загрузили:
+
+
-
- {answer?.split("|")[0]}
- {
- if (answer.length > 0) {
- setReadySend(false)
- await sendAnswer({
- questionId: currentQuestion.id,
- body: "",
- qid: quizId,
- })
- }
- console.log(answer)
- updateAnswer(currentQuestion.id, "", 0);
- setReadySend(true)
- }}
- >
-
-
-
+ {answer?.split("|")[0]}
+ {
+ if (answer.length > 0) {
+ setIsSending(true);
+ await sendAnswer({
+ questionId: currentQuestion.id,
+ body: "",
+ qid: quizId,
+ });
+ }
+ console.log(answer);
+ updateAnswer(currentQuestion.id, "", 0);
+ setIsSending(false);
+ }}
+ >
+
+
- )}
-
- {!answer?.split("|")[0] && (
-
+ ) : (
+
- {
-
- readySend ? <>
-
-
- ) =>
- event.preventDefault()
- }
+ }}
+ >
+ {isSending ?
+
+ :
+
+ uploadFile(e.target.files?.[0])}
+ hidden
+ accept={ACCEPT_SEND_FILE_TYPES_MAP[currentQuestion.content.type].join(",")}
+ multiple
+ type="file"
+ />
+ !answer?.split("|")[0] && setIsDropzoneHighlighted(true)}
+ onDragLeave={() => setIsDropzoneHighlighted(false)}
+ onDragOver={(e) => e.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: theme.palette.background.default,
+ border: `1px solid ${isDropzoneHighlighted ? "red" : "#9A9AAF"}`,
+ borderRadius: "8px",
+ }}
+ >
+
+
+
-
-
-
- {
- UPLOAD_FILE_DESCRIPTIONS_MAP[currentQuestion.content.type]
- .title
- }
-
-
- {
- UPLOAD_FILE_DESCRIPTIONS_MAP[currentQuestion.content.type]
- .description
- }
-
-
-
-
-
-
- > :
-
- }
- setStatusModal(currentQuestion.content.type)} />
-
- )}
- {answer && currentQuestion.content.type === "picture" && (
-
+
+ {UPLOAD_FILE_DESCRIPTIONS_MAP[currentQuestion.content.type].description}
+
+
+
+
+ }
+ setModalWarningType(currentQuestion.content.type)}
/>
- )}
- {answer && currentQuestion.content.type === "video" && (
-
- )}
-
+
+ )}
+ {answer && currentQuestion.content.type === "picture" && (
+
+ )}
+ {answer && currentQuestion.content.type === "video" && (
+
+ )}
setStatusModal("")}
+ open={modalWarningType !== null}
+ onClose={() => setModalWarningType(null)}
>
{
boxShadow: 24,
p: 4,
}}>
-
+
- >
+
);
-
+};
+
+const CurrentModal = ({ status }: { status: ModalWarningType; }) => {
+
+ switch (status) {
+ case null: return null;
+ case 'errorType': return Выбран некорректный тип файла;
+ case 'errorSize': return Файл слишком большой. Максимальный размер 50 МБ;
+ default: return (
+ <>
+ Допустимые расширения файлов:
+ {
+ ACCEPT_SEND_FILE_TYPES_MAP[status].join(" ")}
+ >
+ );
+ }
};
diff --git a/lib/components/ViewPublicationPage/tools/File.tsx b/lib/components/ViewPublicationPage/tools/File.tsx
deleted file mode 100644
index 6598de6..0000000
--- a/lib/components/ViewPublicationPage/tools/File.tsx
+++ /dev/null
@@ -1,63 +0,0 @@
-import { ChangeEvent, useEffect, useRef, useState } from "react";
-import { Box, Button, Typography } from "@mui/material";
-
-import type {
- QuizQuestionFile,
- UploadFileType,
-} from "@model/questionTypes/file";
-
-const UPLOAD_FILE_TYPES_MAP: Record = {
- picture: "image/*",
- video: "video/*",
- audio: "audio/*",
- document:
- ".doc,.docx,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,.pdf",
-} as const;
-
-interface Props {
- question: QuizQuestionFile;
-}
-
-export default function File({ question }: Props) {
- const fileInputRef = useRef(null);
- const [file, setFile] = useState(null);
- const [acceptedType, setAcceptedType] = useState(
- UPLOAD_FILE_TYPES_MAP.picture
- );
-
- useEffect(() => {
- setAcceptedType(UPLOAD_FILE_TYPES_MAP[question.content.type]);
- }, [question.content.type]);
-
- function handleFileChange(event: ChangeEvent) {
- if (!event.target.files?.[0]) return setFile(null);
- setFile(event.target.files[0]);
- }
-
- return (
-
- {question.title}
-
- {file && Выбран файл: {file.name}}
-
- );
-}
diff --git a/lib/components/ViewPublicationPage/tools/fileUpload.ts b/lib/components/ViewPublicationPage/tools/fileUpload.ts
new file mode 100644
index 0000000..641b57c
--- /dev/null
+++ b/lib/components/ViewPublicationPage/tools/fileUpload.ts
@@ -0,0 +1,69 @@
+import { UploadFileType } from "@model/questionTypes/file";
+
+
+export const MAX_FILE_SIZE = 5 * 2 ** 20;
+
+export const UPLOAD_FILE_DESCRIPTIONS_MAP = {
+ picture: {
+ title: "Добавить изображение",
+ description: "Принимает изображения",
+ },
+ video: {
+ title: "Добавить видео",
+ description: "Принимает .mp4 и .mov формат — максимум 50мб",
+ },
+ audio: { title: "Добавить аудиофайл", description: "Принимает аудиофайлы" },
+ document: { title: "Добавить документ", description: "Принимает документы" },
+} as const satisfies Record;
+
+export const ACCEPT_SEND_FILE_TYPES_MAP = {
+ 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",
+ ],
+} as const;