diff --git a/src/components/Forms/Fields/UploadDownloadField.tsx b/src/components/Forms/Fields/UploadDownloadField.tsx index bbcd100..8fdb942 100644 --- a/src/components/Forms/Fields/UploadDownloadField.tsx +++ b/src/components/Forms/Fields/UploadDownloadField.tsx @@ -8,39 +8,58 @@ import { useToast, VStack, } from '@chakra-ui/react'; +import { AxiosResponse } from 'axios'; import { useEffect, useState } from 'react'; import { API } from '../../../data/api'; import useStore from '../../../store'; +import { PolyglotNode } from '../../../types/polyglotElements'; const FileUploadDownload = () => { const [file, setFile] = useState(); - const [nodeId, setNodeId] = useState('1'); + const [nodeId, setNodeId] = useState(); + const [filename, setFilename] = useState(); const toast = useToast(); // Gestione del file selezionato const handleFileChange = (event: any) => { setFile(event.target.files[0]); }; + const { selectedElement } = useStore((store) => ({ + selectedElement: store.getSelectedElement, + })); + useEffect(() => { - setNodeId(useStore.getState().getSelectedNode()?._id || '1'); - console.log(nodeId); - API.downloadFile({ nodeId }).then((response) => { - if (response.data) setFile(response.data); - }); - }, []); + if (!selectedElement) return; + setNodeId((selectedElement as unknown as PolyglotNode)._id); + if (!nodeId) return; + API.downloadFile({ nodeId }) + .then((response) => { + if (response.data) { + const contentDisposition = response.headers['content-disposition']; + const filename = contentDisposition + ?.split('filename=')?.[1] + ?.replace(/"/g, ''); + setFilename(filename); + } + }) + .catch((error: AxiosResponse) => { + console.log(error); + setFilename('Nessun file disponibile'); + }); + }, [selectedElement]); - // Funzione per l'upload const handleUpload = async () => { + if (!nodeId) return; if (!file) { toast({ - title: 'Seleziona un file e inserisci un ID nodo.', + title: 'Select a file.', status: 'warning', }); return; } if (file.type !== 'application/pdf') { toast({ - title: 'Il file selezionato non è un PDF.', + title: 'Selected file must be PDF.', status: 'warning', }); return; @@ -54,42 +73,53 @@ const FileUploadDownload = () => { API.uploadFile({ nodeId, file: formData, - }).then((resp) => - toast({ - title: 'File caricato con successo.\n' + resp.data, - status: 'success', - }) - ); + }) + .then((resp) => + toast({ + title: 'File uploaded successfully.\n' + resp.data, + status: 'success', + }) + ) + .catch((error: AxiosResponse) => { + if (error.status == 413) + toast({ + title: 'Selected file is too Large.\n', + status: 'error', + }); + }); } catch (error) { toast({ - title: 'Errore durante il caricamento del file.', + title: "File's upload failed", status: 'error', }); } }; - // Funzione per il download const handleDownload = async () => { + if (!nodeId) return; try { const response = await API.downloadFile({ nodeId }); - + const contentDisposition = response.headers['content-disposition']; + const filename = contentDisposition + ?.split('filename=')?.[1] + ?.replace(/"/g, ''); const url = window.URL.createObjectURL(new Blob([response.data])); const link = document.createElement('a'); link.href = url; - console.log(response.data.filename); - - console.log(response.data); - link.setAttribute( - 'download', - response.data.filename || 'uploadedFile.pdf' - ); - + link.setAttribute('download', filename || 'uploadedFile.pdf'); document.body.appendChild(link); link.click(); - link.remove(); window.URL.revokeObjectURL(url); - } catch (error) { + + return; + } catch (error: any) { + console.log(error); + if (error.status == 304) + toast({ + title: 'There are no file for this node', + status: 'info', + }); toast({ title: 'Errore durante il download del file.', status: 'error' }); } }; @@ -108,7 +138,7 @@ const FileUploadDownload = () => { Scarica File - + ); }; diff --git a/src/components/LateralMenu/LateralMenu.tsx b/src/components/LateralMenu/LateralMenu.tsx index 23c9ff5..021ff69 100644 --- a/src/components/LateralMenu/LateralMenu.tsx +++ b/src/components/LateralMenu/LateralMenu.tsx @@ -71,6 +71,7 @@ const listImplementedNodes = [ 'ReadMaterialNode', 'WatchVideoNode', 'SummaryNode', + 'ScanningNode', 'codingQuestionNode', 'CollaborativeModelingNode', 'UMLModelingNode', diff --git a/src/components/Modals/AIToolModal.tsx b/src/components/Modals/AIToolModal.tsx index 3c75170..292be28 100644 --- a/src/components/Modals/AIToolModal.tsx +++ b/src/components/Modals/AIToolModal.tsx @@ -21,10 +21,18 @@ import { useToast, } from '@chakra-ui/react'; import { AxiosResponse } from 'axios'; +import { empty } from 'fp-ts/lib/ReadonlyRecord'; import { useState } from 'react'; import { useFormContext } from 'react-hook-form'; import { API } from '../../data/api'; -import { TypeOfExercise } from '../../types/polyglotElements/AIGenerativeTypes/AIGenerativeTypes'; +import { + AIExerciseGenerated, + AIMaterialGenerated, + EducationLevel, + LearningOutcome, + QuestionType, + Topic, +} from '../../types/polyglotElements/AIGenerativeTypes/AIGenerativeTypes'; export type ModaTemplateProps = { isOpen: boolean; @@ -33,16 +41,19 @@ export type ModaTemplateProps = { action?: (i: boolean) => void; }; -export type Topic = { - Topic: string; - Type: TypeOfExercise; - Description: string; -}; - function delay(ms: number) { return new Promise((resolve) => setTimeout(resolve, ms)); } +function shuffleArray(array: T[]) { + const arr = [...array]; + for (let i = arr.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [arr[i], arr[j]] = [arr[j], arr[i]]; + } + return arr; +} + const AIToolModal = ({ isOpen, onClose, @@ -53,19 +64,21 @@ const AIToolModal = ({ const [sourceMaterial, setSourceMaterial] = useState(''); const [titleGen, setTitle] = useState(''); const [macroSubjectGen, setMacroSubject] = useState(''); + const [learningOutcome, setLearningOutcome] = useState(); + const [choosingLearningOutcome, setChoosingLearningOutcome] = + useState(); const [language, setLanguage] = useState(''); - const [level, setLevel] = useState(0); + const [duration, setDuration] = useState(0); + const [eduLevel, setEduLevel] = useState(); const [topicGen, setTopicGen] = useState([ - { Topic: 'prova', Type: 0, Description: '' }, + { topic: 'prova', explanation: '' }, ]); + const [topicIndex, setTopicIndex] = useState(0); - let exerciseType: number; - const [noW, setNoW] = useState(200); + let exerciseType: QuestionType | string; const [ca_n, setCA_N] = useState(1); const [da_n, setDA_N] = useState(1); const [eda_n, setEDA_N] = useState(1); - const [choices, setChoices] = useState(['']); - const [choiceIndex, setChoiceIndex] = useState(0); const [screen1, setScreen1] = useState(true); const [screen2, setScreen2] = useState(false); const [screen3, setScreen3] = useState(false); @@ -74,19 +87,19 @@ const AIToolModal = ({ const word = exType == 'TrueFalseNode' ? 'Statements' : 'Answers'; switch (exType) { case 'closeEndedQuestionNode': - exerciseType = 3; + exerciseType = QuestionType.ShortAnswerQuestion; break; case 'OpenQuestionNode': - exerciseType = 0; + exerciseType = QuestionType.OpenQuestion; break; case 'TrueFalseNode': - exerciseType = 4; + exerciseType = QuestionType.TrueOrFalse; break; case 'multipleChoiceQuestionNode': - exerciseType = 4; + exerciseType = QuestionType.MultipleChoice; break; case 'ReadMaterialNode': - exerciseType = 100; + exerciseType = 'ReadMaterial'; break; default: throw 'error in type'; @@ -134,16 +147,26 @@ const AIToolModal = ({ throw ': no text given'; } const response: AxiosResponse = await API.analyseMaterial({ - material: sourceMaterial, + text: sourceMaterial, }); - setTitle(response.data.Title); - setLanguage(response.data.Language); - setMacroSubject(response.data.MacroSubject); - setLevel(response.data.PerceivedDifficulty); - setTopicGen(response.data.MainTopics); + console.log(response); + setTitle(response.data.title); + setLanguage(response.data.language); + setMacroSubject(response.data.macro_subject); + setLearningOutcome( + response.data.learning_outcome as LearningOutcome + ); + setChoosingLearningOutcome( + response.data.learning_outcome as LearningOutcome + ); + setEduLevel(response.data.education_level as EducationLevel); + setLanguage(response.data.language); + setDuration(response.data.estimated_duration); + setTopicGen(response.data.topics); setScreen1(false); setScreen2(true); } catch (error: any) { + console.log(error); if ((error as Error).name === 'SyntaxError') { toast({ title: 'Invalid syntax', @@ -155,36 +178,37 @@ const AIToolModal = ({ }); return; } - if (error.response.status) { - if (error.response.status == 500) - toast({ - title: 'Material Error', - description: - 'We are sorry, the resource is not analyzable, try with different material. Do not provide pages that are too long (e.g. Wikipedia pages) or too short, as they can not be analyzed correctly', - status: 'error', - duration: 5000, - position: 'bottom-left', - isClosable: true, - }); - else if (error.response.status != 200) + if (error.response) + if (error.response.status) { + if (error.response.status == 500) + toast({ + title: 'Material Error', + description: + 'We are sorry, the resource is not analyzable, try with different material. Do not provide pages that are too long (e.g. Wikipedia pages) or too short, as they can not be analyzed correctly', + status: 'error', + duration: 5000, + position: 'bottom-left', + isClosable: true, + }); + else if (error.response.status != 200) + toast({ + title: 'AI API Error', + description: + 'Internal Server error, try again. If the error persists try change material.', + status: 'error', + duration: 5000, + position: 'bottom-left', + isClosable: true, + }); + } else toast({ - title: 'AI API Error', - description: - 'Internal Server error, try again. If the error persists try change material.', + title: 'Generic Error', + description: 'Try later ' + (error as Error), status: 'error', duration: 5000, position: 'bottom-left', isClosable: true, }); - } else - toast({ - title: 'Generic Error', - description: 'Try later ' + (error as Error), - status: 'error', - duration: 5000, - position: 'bottom-left', - isClosable: true, - }); } finally { setGeneratingLoading(false); } @@ -203,19 +227,19 @@ const AIToolModal = ({ paddingTop={'5px'} paddingBottom={'-5px'} > - Level: + Educational Level: @@ -238,7 +262,7 @@ const AIToolModal = ({ {topicGen.map((p, id) => { return ( ); })} @@ -254,32 +278,12 @@ const AIToolModal = ({ > Topic Description: - {topicGen[topicIndex].Description} + {topicGen[topicIndex].explanation}