From 01ab439f02f43013274d0afdf64fcea1a59decdc Mon Sep 17 00:00:00 2001 From: gilles-arnout Date: Mon, 20 May 2024 21:19:53 +0200 Subject: [PATCH 1/5] added all submissions page --- .../components/ProjectDetailsPage.tsx | 420 +++++++++--------- .../project/[project_id]/submissions/page.tsx | 39 ++ frontend/locales/en/common.json | 3 +- frontend/locales/nl/common.json | 3 +- 4 files changed, 259 insertions(+), 206 deletions(-) create mode 100644 frontend/app/[locale]/project/[project_id]/submissions/page.tsx diff --git a/frontend/app/[locale]/components/ProjectDetailsPage.tsx b/frontend/app/[locale]/components/ProjectDetailsPage.tsx index d0578790..95b9048f 100644 --- a/frontend/app/[locale]/components/ProjectDetailsPage.tsx +++ b/frontend/app/[locale]/components/ProjectDetailsPage.tsx @@ -1,10 +1,10 @@ 'use client' -import React, { useEffect, useState } from "react"; -import {checkGroup, getGroup, getProject, getUserData, Project, UserData} from "@lib/api"; -import { useTranslation } from "react-i18next"; +import React, {useEffect, useState} from "react"; +import {checkGroup, getProject, getUserData, Project, UserData} from "@lib/api"; +import {useTranslation} from "react-i18next"; import Box from "@mui/material/Box"; import Typography from "@mui/material/Typography"; -import { Grid, IconButton, LinearProgress, ThemeProvider } from "@mui/material"; +import {Grid, IconButton, LinearProgress, ThemeProvider} from "@mui/material"; import ProjectSubmissionsList from "@app/[locale]/components/ProjectSubmissionsList"; import GroupSubmissionList from "@app/[locale]/components/GroupSubmissionList"; import baseTheme from "@styles/theme"; @@ -22,223 +22,235 @@ import AccessTimeIcon from "@mui/icons-material/AccessTime"; const backend_url = process.env["NEXT_PUBLIC_BACKEND_URL"]; interface ProjectDetailsPageProps { - locale: any; - project_id: number; + locale: any; + project_id: number; } const ProjectDetailsPage: React.FC = ({ - locale, - project_id, -}) => { - const { t } = useTranslation(); + locale, + project_id, + }) => { + const {t} = useTranslation(); - const [project, setProject] = useState(); - const [loadingProject, setLoadingProject] = useState(true); - const [user, setUser] = useState(null); - const [isExpanded, setIsExpanded] = useState(false); - const [isInGroup, setIsInGroup] = useState(false); - const previewLength = 300; - const deadlineColorType = project?.deadline - ? checkDeadline(project.deadline) - : "textSecondary"; - const deadlineColor = - baseTheme.palette[deadlineColorType]?.main || - baseTheme.palette.text.secondary; + const [project, setProject] = useState(); + const [loadingProject, setLoadingProject] = useState(true); + const [user, setUser] = useState(null); + const [isExpanded, setIsExpanded] = useState(false); + const [isInGroup, setIsInGroup] = useState(false); + const previewLength = 300; + const deadlineColorType = project?.deadline + ? checkDeadline(project.deadline) + : "textSecondary"; + const deadlineColor = + baseTheme.palette[deadlineColorType]?.main || + baseTheme.palette.text.secondary; - useEffect(() => { - const fetchUser = async () => { - try { - setUser(await getUserData()); - } catch (error) { - console.error("There was an error fetching the user data:", error); - } - }; + useEffect(() => { + const fetchUser = async () => { + try { + setUser(await getUserData()); + } catch (error) { + console.error("There was an error fetching the user data:", error); + } + }; - fetchUser(); - }, []); + fetchUser(); + }, []); - useEffect(() => { - const fetchProject = async () => { - try { - setProject(await getProject(project_id)); - } catch (error) { - console.error("There was an error fetching the project:", error); - } - }; - - fetchProject().then(() => setLoadingProject(false)); - checkGroup(project_id).then((response) => setIsInGroup(response)); - }, [project_id]); + useEffect(() => { + const fetchProject = async () => { + try { + setProject(await getProject(project_id)); + } catch (error) { + console.error("There was an error fetching the project:", error); + } + }; - if (loadingProject) { - return ; - } + fetchProject().then(() => setLoadingProject(false)); + checkGroup(project_id).then((response) => setIsInGroup(response)); + }, [project_id]); - const toggleDescription = () => { - setIsExpanded(!isExpanded); - }; + if (loadingProject) { + return ; + } - function formatDate(isoString: string): string { - const options: Intl.DateTimeFormatOptions = { - year: "numeric", - month: "long", - day: "numeric", - hour: "2-digit", - minute: "2-digit", - hour12: false, + const toggleDescription = () => { + setIsExpanded(!isExpanded); }; - const date = new Date(isoString); - return date.toLocaleString(locale, options); - } - function checkDeadline(deadline) { - const now = new Date(); - const deadlineDate = new Date(deadline); - return now < deadlineDate ? "success" : "failure"; - } + function formatDate(isoString: string): string { + const options: Intl.DateTimeFormatOptions = { + year: "numeric", + month: "long", + day: "numeric", + hour: "2-digit", + minute: "2-digit", + hour12: false, + }; + const date = new Date(isoString); + return date.toLocaleString(locale, options); + } - return ( - - - - - - - - {project?.name} - - - - {user?.role !== 3 && ( - - - - )} - - - - - - - - {t("assignment")} - - {project?.description && - project?.description.length > previewLength && - !isExpanded - ? `${project?.description.substring(0, previewLength)}...` - : project?.description} - - {project?.description && project?.description.length > previewLength && ( - - {isExpanded ? : } - - )} - {t("required_files")} - + function checkDeadline(deadline) { + const now = new Date(); + const deadlineDate = new Date(deadline); + return now < deadlineDate ? "success" : "failure"; + } + + return ( + + + + + + + + {project?.name} + + + + {user?.role !== 3 && ( + <> + + + + + + + + )} + + + + + + + + {t("assignment")} + + {project?.description && + project?.description.length > previewLength && + !isExpanded + ? `${project?.description.substring(0, previewLength)}...` + : project?.description} + + {project?.description && project?.description.length > previewLength && ( + + {isExpanded ? : } + + )} + {t("required_files")} +
                     {generateDirectoryTree(project?.file_structure).split('\n').map((line: string, index: number) => (
-                            
-                                {line}
-                                
-
+ + {line} +
+
))}
-
- {t("conditions")} - {project?.conditions} - - {t("max_score")}: - {project?.max_score} - - - {t("number_of_groups")}: - {project?.number_of_groups} - - - {t("group_size")}: - {project?.group_size} - - {user?.role !== 3 && ( - - )} -
- - {t("submissions")} -
- - - {project?.deadline ? formatDate(project.deadline) : "No Deadline"} - -
- {user?.role === 3 ? ( - isInGroup ? ( - - ) : ( - - {t("not_in_group")} - - ) - ) : null} -
- - {user?.role === 3 ? ( - - ) : ( - - )} - -
-
-
- ); +
+ {t("conditions")} + {project?.conditions} + + {t("max_score")}: + {project?.max_score} + + + {t("number_of_groups")}: + {project?.number_of_groups} + + + {t("group_size")}: + {project?.group_size} + + {user?.role !== 3 && ( + + )} +
+ + {t("submissions")} +
+ + + {project?.deadline ? formatDate(project.deadline) : "No Deadline"} + +
+ {user?.role === 3 ? ( + isInGroup ? ( + + ) : ( + + {t("not_in_group")} + + ) + ) : null} +
+ + {user?.role === 3 ? ( + + ) : ( + + )} + +
+
+
+ ); }; function buildTree(paths) { diff --git a/frontend/app/[locale]/project/[project_id]/submissions/page.tsx b/frontend/app/[locale]/project/[project_id]/submissions/page.tsx new file mode 100644 index 00000000..4bb74a40 --- /dev/null +++ b/frontend/app/[locale]/project/[project_id]/submissions/page.tsx @@ -0,0 +1,39 @@ +import initTranslations from "@app/i18n"; +import TranslationsProvider from "@app/[locale]/components/TranslationsProvider"; +import NavBar from "@app/[locale]/components/NavBar"; +import ArrowBackIcon from "@mui/icons-material/ArrowBack"; +import {Box, Button} from "@mui/material"; +import React from "react"; +import ProjectSubmissionsList from "@app/[locale]/components/ProjectSubmissionsList"; + +const i18nNamespaces = ['common'] + +export default async function SubmissionsPage({params}: { params: { locale: any, project_id: number } }) { + const {locale, project_id: projectId} = params; + const {t, resources} = await initTranslations(locale, i18nNamespaces); + + return ( + + + + + + + + ); +} diff --git a/frontend/locales/en/common.json b/frontend/locales/en/common.json index 4730716c..b306a73e 100644 --- a/frontend/locales/en/common.json +++ b/frontend/locales/en/common.json @@ -138,5 +138,6 @@ "join/leave": "Join/Leave", "group_nr": "Group nr", "join_leave": "Join/Leave", - "not_in_group": "Join a group to submit" + "not_in_group": "Join a group to submit", + "submission_all": "Submissions" } \ No newline at end of file diff --git a/frontend/locales/nl/common.json b/frontend/locales/nl/common.json index 16a66b81..af0852b1 100644 --- a/frontend/locales/nl/common.json +++ b/frontend/locales/nl/common.json @@ -141,5 +141,6 @@ "join/leave": "Toetreden/Verlaten", "group_nr": "Groep nr", "join_leave": "Toetreden/Verlaten", - "not_in_group": "Je kan niet indienen zonder in een groep te zitten" + "not_in_group": "Je kan niet indienen zonder in een groep te zitten", + "submission_all": "Indieningen" } \ No newline at end of file From b2342526da2ab9170861fb95339a144a3a118c3d Mon Sep 17 00:00:00 2001 From: gilles-arnout Date: Mon, 20 May 2024 21:21:32 +0200 Subject: [PATCH 2/5] added all submissions page --- frontend/app/[locale]/components/ProjectDetailsPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/app/[locale]/components/ProjectDetailsPage.tsx b/frontend/app/[locale]/components/ProjectDetailsPage.tsx index 95b9048f..fa498e5d 100644 --- a/frontend/app/[locale]/components/ProjectDetailsPage.tsx +++ b/frontend/app/[locale]/components/ProjectDetailsPage.tsx @@ -293,4 +293,4 @@ function generateDirectoryTree(filePaths) { return `.\n${buildTreeString(tree)}`; } -export default ProjectDetailsPage; \ No newline at end of file +export default ProjectDetailsPage; From 4813326581e2be25f56cf6fea54fdd4fe2048114 Mon Sep 17 00:00:00 2001 From: gilles-arnout Date: Wed, 22 May 2024 09:11:48 +0200 Subject: [PATCH 3/5] precommit --- .../components/ProjectDetailsPage.tsx | 4 ++++ .../app/[locale]/components/StatusButton.tsx | 20 +++++++++++-------- .../components/SubmissionDetailsPage.tsx | 10 +++++----- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/frontend/app/[locale]/components/ProjectDetailsPage.tsx b/frontend/app/[locale]/components/ProjectDetailsPage.tsx index fa498e5d..507028ce 100644 --- a/frontend/app/[locale]/components/ProjectDetailsPage.tsx +++ b/frontend/app/[locale]/components/ProjectDetailsPage.tsx @@ -255,6 +255,10 @@ const ProjectDetailsPage: React.FC = ({ function buildTree(paths) { const tree = {}; + if (!paths) { + return tree; + } + const paths_list = paths.split(','); paths_list.forEach(path => { const parts = path.split('/'); diff --git a/frontend/app/[locale]/components/StatusButton.tsx b/frontend/app/[locale]/components/StatusButton.tsx index c809017c..a469cce4 100644 --- a/frontend/app/[locale]/components/StatusButton.tsx +++ b/frontend/app/[locale]/components/StatusButton.tsx @@ -44,14 +44,18 @@ function StatusButton( ); } -function getStart(file: string) { - if (file[0] === '+') { - return 0; - } else if (file[0] === '~') { - return 1; - } else { - return 2; - } +function getStart(file: string | undefined) { + if (!file || file.length === 0) { + return 2; + } + + if (file[0] === '+') { + return 0; + } else if (file[0] === '~') { + return 1; + } else { + return 2; + } } export default StatusButton; \ No newline at end of file diff --git a/frontend/app/[locale]/components/SubmissionDetailsPage.tsx b/frontend/app/[locale]/components/SubmissionDetailsPage.tsx index a8b1a1d1..14f5927b 100644 --- a/frontend/app/[locale]/components/SubmissionDetailsPage.tsx +++ b/frontend/app/[locale]/components/SubmissionDetailsPage.tsx @@ -12,12 +12,12 @@ import DownloadIcon from "@mui/icons-material/CloudDownload"; const backend_url = process.env['NEXT_PUBLIC_BACKEND_URL']; -interface ProjectDetailsPageProps { +interface SubmissionDetailsPageProps { locale: any, submission_id: number; } -const ProjectDetailsPage: React.FC = ({ locale, submission_id }) => { +const SubmissionDetailsPage: React.FC = ({ locale, submission_id }) => { const { t } = useTranslation(); const [submission, setSubmission] = useState(); @@ -67,7 +67,7 @@ const ProjectDetailsPage: React.FC = ({ locale, submiss - + @@ -107,7 +107,7 @@ const ProjectDetailsPage: React.FC = ({ locale, submiss startIcon={} href={`${backend_url}/submissions/${submission_id}/download`} download - size="small" // Adjust button size + size="small" > {t("download_file")} @@ -121,4 +121,4 @@ const ProjectDetailsPage: React.FC = ({ locale, submiss ); }; -export default ProjectDetailsPage; +export default SubmissionDetailsPage; From 39f011b2bd9b03443c26b159d7ff35f3d60e0084 Mon Sep 17 00:00:00 2001 From: gilles-arnout Date: Wed, 22 May 2024 16:43:30 +0200 Subject: [PATCH 4/5] re added all submission page --- .../components/ProjectDetailsPage.tsx | 47 ++++++++++++------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/frontend/app/[locale]/components/ProjectDetailsPage.tsx b/frontend/app/[locale]/components/ProjectDetailsPage.tsx index c93fbf92..d2374f8d 100644 --- a/frontend/app/[locale]/components/ProjectDetailsPage.tsx +++ b/frontend/app/[locale]/components/ProjectDetailsPage.tsx @@ -154,22 +154,37 @@ const ProjectDetailsPage: React.FC = ({ /> ))) : ( <> - {user?.role !== 3 && ( - - )} + {user?.role !== 3 && ( + <> + + + + )} + + {t('all_submissions')} +