diff --git a/frontend/public/locales/en/translation.json b/frontend/public/locales/en/translation.json index 3dee8916..9b3a1eb6 100644 --- a/frontend/public/locales/en/translation.json +++ b/frontend/public/locales/en/translation.json @@ -51,6 +51,8 @@ }, "create_project": { "title": "Create project", + "success": "Your project has been successfully saved.", + "failed": "Something went wrong while saving your project. Please try again.", "name": { "tag": "Project name:", "placeholder": "Enter a name" diff --git a/frontend/public/locales/nl/translation.json b/frontend/public/locales/nl/translation.json index 0ab47578..34abc255 100644 --- a/frontend/public/locales/nl/translation.json +++ b/frontend/public/locales/nl/translation.json @@ -51,6 +51,8 @@ }, "create_project": { "title": "Maak een project aan", + "success": "Uw project is succesvol opgeslagen.", + "failed": "Er is iets fout gegaan tijdens het opslaan van uw project. Probeer het opnieuw.", "name": { "tag": "Projectnaam:", "placeholder": "Voer een naam in" diff --git a/frontend/src/components/ProjectTeacherComponent.tsx b/frontend/src/components/ProjectTeacherComponent.tsx index 4f0f813c..a12b3b78 100644 --- a/frontend/src/components/ProjectTeacherComponent.tsx +++ b/frontend/src/components/ProjectTeacherComponent.tsx @@ -2,7 +2,7 @@ import {ChangeEvent, JSX, useEffect, useRef, useState} from "react"; import Inputfield from "./Inputfield.tsx"; import {SelectionBox} from "./SelectionBox.tsx"; import 'react-calendar/dist/Calendar.css'; -import {FaUpload} from "react-icons/fa"; +import {FaEraser, FaUpload} from "react-icons/fa"; import {ProjectTeacher, Value} from "../types/project.ts"; import "../assets/styles/teacher_components.css" import SimpleTests from "./SimpleTests/SimpleTests.tsx"; @@ -13,19 +13,23 @@ import Statistics from "./Statistics.tsx"; import {RegularButton} from "./RegularButton.tsx"; import {FaDownload} from "react-icons/fa6"; import _ from 'lodash'; -import { FaEraser } from "react-icons/fa"; -import { getScrollbarWidth } from "../utils/ScrollBarWidth.ts"; +import {ProjectInput} from "../utils/InputInterfaces.ts"; +import {course_create_project} from "../utils/api/Course.ts"; +import {Project} from "../utils/ApiInterfaces.ts"; +import {useNavigate} from "react-router-dom"; +import {update_project} from "../utils/api/Project.ts"; +import {getScrollbarWidth} from "../utils/ScrollBarWidth.ts"; import Switch from "react-switch"; -export function ProjectTeacherComponent(props: { - project: ProjectTeacher, - submission_statistics: {[key: number]: number} | undefined, - download_all_submissions: (() => Promise) | undefined - is_new?: boolean +export function ProjectTeacherComponent(props: { + project: ProjectTeacher, + submission_statistics: { [key: number]: number } | undefined, + download_all_submissions: (() => Promise) | undefined, + updateTitle?: (name: string) => void, + is_new?: boolean, }): JSX.Element { - + const navigate = useNavigate(); const {t} = useTranslation(); - const [projectName, setProjectName] = useState(props.project.projectName) const [courseName, setCourseName] = useState(props.project.courseName) const [hours, setHours] = useState(props.project.hours); @@ -34,6 +38,10 @@ export function ProjectTeacherComponent(props: { const [description, setDescription] = useState(props.project.description); const [max_students, setMaxStudents] = useState(props.project.maxGroupMembers); const [requiredFiles, setRequiredFiles] = useState(props.project.requiredFiles); + const [visible, setVisible] = useState(props.project.visible) + const [archived, setArchived] = useState(props.project.archived) + const [success, isSuccess] = useState(undefined) + // Deze wordt niet gebruikt. Dit zit verwerkt in het json-object als OnlyPresentConstraint. // const [otherFilesAllow, setOtherFilesAllow] = useState(props.project.otherFilesAllow); const [groupProject, setGroupProject] = useState(props.project.groupProject); @@ -53,35 +61,23 @@ export function ProjectTeacherComponent(props: { value7: max_students, value8: requiredFiles, value9: groupProject, - value10: dockerString + value10: dockerString, + value11: visible, + value12: archived }); - useEffect(() => { - setInitialValues({ - value1: projectName, - value2: courseName, - value3: hours, - value4: minutes, - value5: deadline, - value6: description, - value7: max_students, - value8: requiredFiles, - value9: groupProject, - value10: dockerString - }); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - function allowSaveButton(): boolean { - const first_part = _.isEqual(projectName, initialValues.value1) && - _.isEqual(courseName, initialValues.value2) && - _.isEqual(hours, initialValues.value3) && - _.isEqual(minutes, initialValues.value4) && - _.isEqual(description, initialValues.value6) && + const first_part = _.isEqual(projectName, initialValues.value1) && + _.isEqual(courseName, initialValues.value2) && + _.isEqual(hours, initialValues.value3) && + _.isEqual(minutes, initialValues.value4) && + _.isEqual(description, initialValues.value6) && _.isEqual(max_students, initialValues.value7) && - _.isEqual(requiredFiles,initialValues.value8) && + _.isEqual(requiredFiles, initialValues.value8) && _.isEqual(groupProject, initialValues.value9) && - _.isEqual(dockerString, initialValues.value10); + _.isEqual(dockerString, initialValues.value10) && + _.isEqual(visible, initialValues.value11) && + _.isEqual(archived, initialValues.value12); const second_part_1 = (deadline as Date).toDateString(); const second_part_2 = (initialValues.value5 as Date).toDateString(); const second_part = _.isEqual(second_part_1, second_part_2); @@ -101,7 +97,11 @@ export function ProjectTeacherComponent(props: { // SimpleTests const [requiredFilesHasChanged, setRequiredFilesHasChanged] = useState(false); - if (requiredFilesHasChanged) {if (!requiredFilesHasChanged) {console.log("")}} // eslint prevent error + if (requiredFilesHasChanged) { + if (!requiredFilesHasChanged) { + console.log("") + } + } // eslint prevent error // Docker const dockerRef = useRef(null); @@ -140,7 +140,7 @@ export function ProjectTeacherComponent(props: { } function handleDownloadDocker() { - const blob = new Blob([dockerString], { type: 'text/plain' }); + const blob = new Blob([dockerString], {type: 'text/plain'}); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; @@ -151,25 +151,78 @@ export function ProjectTeacherComponent(props: { document.body.removeChild(a); } + async function handleSaveClick() { + const projectInput: ProjectInput = { + name: projectName, + deadline: (deadline as Date).toISOString(), + visible: visible, + archived: archived, + description: description, + requirements: JSON.stringify(requiredFiles), + max_students: max_students == 0 ? 1 : max_students, + dockerfile: dockerString + } + + const course = props.project.all_courses.find(project => project.course_name == props.project.courseName) + if (!course) { + return; + } + + if (props.project.projectId == -1) { + // Create new project + const new_project: Project = await course_create_project(course.course_id, projectInput) + await new Promise(resolve => setTimeout(resolve, 500)) + navigate(`/teacher/project/${new_project.project_id}`) + } else { + // Update project + const updated_project: boolean = await update_project(props.project.projectId, projectInput) + isSuccess(updated_project); + if (updated_project) { + setInitialValues({ + value1: projectName, + value2: courseName, + value3: hours, + value4: minutes, + value5: deadline, + value6: description, + value7: max_students, + value8: requiredFiles, + value9: groupProject, + value10: dockerString, + value11: visible, + value12: archived + }); + } + if (props.updateTitle) { + props.updateTitle(projectName) + } + await new Promise(resolve => setTimeout(resolve, 3000)) + isSuccess(undefined) + } + } + const [width, setWidth] = useState('100%'); useEffect(() => { - const scrollbarWidth = getScrollbarWidth(); - setWidth(`calc(100vw - var(--sidebar-width) - ${scrollbarWidth}px)`); - console.log(scrollbarWidth) + const scrollbarWidth = getScrollbarWidth(); + setWidth(`calc(100vw - var(--sidebar-width) - ${scrollbarWidth}px)`); + console.log(scrollbarWidth) }, []); return (
- {}} - disabled={!allowSaveButton()} - primary={allowSaveButton()}/> {/* TODO: implement save */} + + { + void handleSaveClick() + }} + disabled={!allowSaveButton()} + primary={allowSaveButton()}/>
{props.submission_statistics !== undefined && }
- {props.download_all_submissions !== undefined && + {props.download_all_submissions !== undefined &&
+ {/* Result Save */} + {success &&
+ {t('create_project.success')} +
} + + {success !== undefined && !success && +
+ {t('create_project.failed')} +
} {/* PROJECT NAME FIELD */}
@@ -201,7 +263,7 @@ export function ProjectTeacherComponent(props: {
+ setValue={setCourseName}/>
{/* DEADLINE FIELD */} @@ -209,18 +271,19 @@ export function ProjectTeacherComponent(props: {
-
+
setDeadline(date)} value={deadline} - locale={t('create_project.deadline.locale')}/> + locale={t('create_project.deadline.locale')}/>
+ setValue={setHours} value_as_number={true}/> + setValue={setMinutes} value_as_number={true}/>
@@ -233,8 +296,8 @@ export function ProjectTeacherComponent(props: {
{/* Deze moet er blijven, anders doet css raar*/}