From 24c90162c5448442058793ecd43093d1a4079c06 Mon Sep 17 00:00:00 2001 From: elias Date: Sat, 18 May 2024 21:12:20 +0200 Subject: [PATCH 01/24] added secondary button in custom components --- .../src/components/CustomComponents.tsx | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/frontend/frontend/src/components/CustomComponents.tsx b/frontend/frontend/src/components/CustomComponents.tsx index 21d8c38e..8fc4d6e3 100644 --- a/frontend/frontend/src/components/CustomComponents.tsx +++ b/frontend/frontend/src/components/CustomComponents.tsx @@ -1,3 +1,4 @@ +import { darken,lighten } from '@mui/system'; import { Button as BaseButton, Card as BaseCard, @@ -13,12 +14,33 @@ export const Button = ({ children, ...props }: any) => { size="large" sx={{ maxHeight: '35px', - bgcolor: 'primary.main', + backgroundColor: 'primary.main', textTransform: 'none', color: 'primary.contrastText', '&:hover': { - backgroundColor: 'secondary.main', - color: 'secondary.contrastText', + backgroundColor: darken(theme.palette.primary.main,0.5), + }, + }} + {...props} + > + {children} + + ) +} + +export const SecundaryButton = ({ children, ...props }: any) => { + return ( + { } export default { Button, Card, Divider } +`` \ No newline at end of file From 376097f51af320e28a81ed61d33b43d68ed3d40b Mon Sep 17 00:00:00 2001 From: elias Date: Sat, 18 May 2024 21:30:40 +0200 Subject: [PATCH 02/24] fixed subject page --- frontend/frontend/src/components/CustomComponents.tsx | 1 - frontend/frontend/src/pages/subjectsPage/ProjectsView.tsx | 2 ++ frontend/frontend/src/pages/subjectsPage/StudentPopUp.tsx | 8 +++----- frontend/frontend/src/pages/subjectsPage/SubjectsPage.tsx | 4 ++-- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/frontend/frontend/src/components/CustomComponents.tsx b/frontend/frontend/src/components/CustomComponents.tsx index 8fc4d6e3..50dca8a5 100644 --- a/frontend/frontend/src/components/CustomComponents.tsx +++ b/frontend/frontend/src/components/CustomComponents.tsx @@ -81,4 +81,3 @@ export const Divider = ({ children, ...props }: any) => { } export default { Button, Card, Divider } -`` \ No newline at end of file diff --git a/frontend/frontend/src/pages/subjectsPage/ProjectsView.tsx b/frontend/frontend/src/pages/subjectsPage/ProjectsView.tsx index cbd51900..74e72937 100644 --- a/frontend/frontend/src/pages/subjectsPage/ProjectsView.tsx +++ b/frontend/frontend/src/pages/subjectsPage/ProjectsView.tsx @@ -150,6 +150,7 @@ export function ProjectsView({ return ( <> + + ) } diff --git a/frontend/frontend/src/pages/subjectsPage/StudentPopUp.tsx b/frontend/frontend/src/pages/subjectsPage/StudentPopUp.tsx index 7d5529bb..7628bb67 100644 --- a/frontend/frontend/src/pages/subjectsPage/StudentPopUp.tsx +++ b/frontend/frontend/src/pages/subjectsPage/StudentPopUp.tsx @@ -1,7 +1,7 @@ import { User } from './AddChangeSubjectPage' import * as React from 'react' import { IconButton, List, ListItem, ListItemText, Typography } from '@mui/material' -import { Button } from '../../components/CustomComponents' +import {Button, SecundaryButton} from '../../components/CustomComponents' import Dialog from '@mui/material/Dialog' import DialogTitle from '@mui/material/DialogTitle' import CloseIcon from '@mui/icons-material/Close' @@ -23,15 +23,13 @@ export default function StudentPopUp({ students, text }: StudentPopUpProps) { return ( <> {/* Students Button */} - + {/* Students Dialog */} - - + )} From a7afed7365fd4caeb4b03063ccadf5a7da41e35a Mon Sep 17 00:00:00 2001 From: elias Date: Sat, 18 May 2024 23:20:57 +0200 Subject: [PATCH 03/24] added evenlyspaced row and added it to assignmentPage --- .../src/components/CustomComponents.tsx | 32 ++- .../SubmissionListItemStudentPage.tsx | 66 ++--- .../SubmissionListItemTeacherPage.tsx | 83 +++--- .../pages/assignmentPage/AssignmentPage.tsx | 236 ++++++------------ 4 files changed, 172 insertions(+), 245 deletions(-) diff --git a/frontend/frontend/src/components/CustomComponents.tsx b/frontend/frontend/src/components/CustomComponents.tsx index 50dca8a5..d879e97d 100644 --- a/frontend/frontend/src/components/CustomComponents.tsx +++ b/frontend/frontend/src/components/CustomComponents.tsx @@ -3,6 +3,7 @@ import { Button as BaseButton, Card as BaseCard, Divider as BaseDivider, + Box } from '@mui/material' import theme from '../Theme.ts' @@ -80,4 +81,33 @@ export const Divider = ({ children, ...props }: any) => { ) } -export default { Button, Card, Divider } +export const EvenlySpacedRow = ({items}) => { + return ( + + {items.map((item, index) => ( + + + + {item} + + + ))} + + ) +} + + + +export default { Button, Card, Divider, EvenlySpacedRow } diff --git a/frontend/frontend/src/components/SubmissionListItemStudentPage.tsx b/frontend/frontend/src/components/SubmissionListItemStudentPage.tsx index d5ed7d60..fd19610b 100644 --- a/frontend/frontend/src/components/SubmissionListItemStudentPage.tsx +++ b/frontend/frontend/src/components/SubmissionListItemStudentPage.tsx @@ -1,3 +1,4 @@ +import { EvenlySpacedRow} from "./CustomComponents.tsx"; import { ListItem, ListItemButton, @@ -49,46 +50,31 @@ export function SubmissionListItemStudentPage({ return ( <> - - - {/* Display submission id */} - - {/* Display submission timestamp */} - - {/* Display submission status icon */} - - {status ? ( - - ) : ( - - )} - + + + , + , + + {status ? ( + + ) : ( + + )} + + ]}/> diff --git a/frontend/frontend/src/components/SubmissionListItemTeacherPage.tsx b/frontend/frontend/src/components/SubmissionListItemTeacherPage.tsx index 27a4f734..2904972e 100644 --- a/frontend/frontend/src/components/SubmissionListItemTeacherPage.tsx +++ b/frontend/frontend/src/components/SubmissionListItemTeacherPage.tsx @@ -13,6 +13,7 @@ import instance from '../axiosConfig' import { Submission } from '../pages/submissionPage/SubmissionPage.tsx' import { t } from 'i18next' import dayjs from 'dayjs' +import {EvenlySpacedRow} from "./CustomComponents.tsx"; interface SubmissionListItemTeacherPageProps { relative_group_id: string @@ -126,21 +127,11 @@ export function SubmissionListItemTeacherPage({ return ( <> - + - {/* Display group id */} - - {/* Display submission timestamp */} - - {/* Display score */} - - {/* Display submission status icon */} - - {!submitted?.status ? ( - - ) : ( - submitted !== undefined && ( - - ) - )} - - {/* Display download icon */} - + />, + , + , + + {!submitted?.status ? ( + + ) : ( + submitted !== undefined && ( + + ) + )} + ,
{submitted ? ( @@ -200,7 +186,8 @@ export function SubmissionListItemTeacherPage({ )}
-
+ ]}> +
diff --git a/frontend/frontend/src/pages/assignmentPage/AssignmentPage.tsx b/frontend/frontend/src/pages/assignmentPage/AssignmentPage.tsx index 27d0e5f4..9ad89bfc 100644 --- a/frontend/frontend/src/pages/assignmentPage/AssignmentPage.tsx +++ b/frontend/frontend/src/pages/assignmentPage/AssignmentPage.tsx @@ -2,12 +2,10 @@ import { Header } from '../../components/Header.tsx' import FileUploadButton from '../../components/FileUploadButton.tsx' import { SubmissionListItemStudentPage } from '../../components/SubmissionListItemStudentPage.tsx' import { SubmissionListItemTeacherPage } from '../../components/SubmissionListItemTeacherPage.tsx' +import {Card, Button, Divider, EvenlySpacedRow} from '../../components/CustomComponents.tsx' import { Box, - Button, - Card, CircularProgress, - Divider, List, Skeleton, Stack, @@ -367,15 +365,7 @@ export function AssignmentPage() { {/* Assignment description */} - + - - + + {t('group')} - - + , + {t('time')} - - + , + Score - - + , + Status - - + , + {t('download')} - + ]} + /> - {loading ? ( [...Array(3)].map((_, index) => ( )) ) : ( - + {groups.map((group) => ( - - + + group.groep_id + ) + ) + + 1 + ).toString()} + group_id={group.groep_id.toString()} + assignment_id={ + assignmentId + ? assignmentId + : '' } - justifyContent={ - 'space-between' + course_id={ + courseId + ? courseId + : '' } - pl={3} - pr={3} - > - - group.groep_id - ) - ) + - 1 - ).toString()} - group_id={group.groep_id.toString()} - assignment_id={ - assignmentId - ? assignmentId - : '' - } - course_id={ - courseId - ? courseId - : '' - } - /> - + /> ))} @@ -703,15 +665,7 @@ export function AssignmentPage() { {/* Assignment */} - + - - + {t('submission')} - - + , + {t('time')} - - + , + Status - + ]}/> - - - + + submission.indiening_id + ) + ) + + 1 + ).toString()} + timestamp={dayjs( + submission.tijdstip + ).format( + 'DD/MM/YYYY HH:mm' + )} + status={ + submission.status > + 0 } - pl={ - 3 + assignment_id={ + assignmentId + ? assignmentId + : '' } - pr={ - 3 + course_id={ + courseId + ? courseId + : '' } - > - - submission.indiening_id - ) - ) + - 1 - ).toString()} - timestamp={dayjs( - submission.tijdstip - ).format( - 'DD/MM/YYYY HH:mm' - )} - status={ - submission.status > - 0 - } - assignment_id={ - assignmentId - ? assignmentId - : '' - } - course_id={ - courseId - ? courseId - : '' - } - /> - + /> ) ) From b565725e526aa9808b1e10834e27ecd9302acb45 Mon Sep 17 00:00:00 2001 From: elias Date: Sun, 19 May 2024 10:25:50 +0200 Subject: [PATCH 04/24] alignment fixed for assignment and subjectpage --- .../src/components/CustomComponents.tsx | 6 +- .../SubmissionListItemStudentPage.tsx | 23 ++++--- .../SubmissionListItemTeacherPage.tsx | 64 +++++++++-------- .../pages/assignmentPage/AssignmentPage.tsx | 68 +++++++++++-------- .../AssignmentListItemSubjectsPage.tsx | 46 ++++--------- .../src/pages/subjectsPage/ProjectsView.tsx | 37 ++++------ 6 files changed, 119 insertions(+), 125 deletions(-) diff --git a/frontend/frontend/src/components/CustomComponents.tsx b/frontend/frontend/src/components/CustomComponents.tsx index d879e97d..8551f35d 100644 --- a/frontend/frontend/src/components/CustomComponents.tsx +++ b/frontend/frontend/src/components/CustomComponents.tsx @@ -92,12 +92,12 @@ export const EvenlySpacedRow = ({items}) => { {item} diff --git a/frontend/frontend/src/components/SubmissionListItemStudentPage.tsx b/frontend/frontend/src/components/SubmissionListItemStudentPage.tsx index fd19610b..68840f6f 100644 --- a/frontend/frontend/src/components/SubmissionListItemStudentPage.tsx +++ b/frontend/frontend/src/components/SubmissionListItemStudentPage.tsx @@ -4,6 +4,7 @@ import { ListItemButton, ListItemIcon, ListItemText, + Box, } from '@mui/material' import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline' import HighlightOffIcon from '@mui/icons-material/HighlightOff' @@ -50,7 +51,7 @@ export function SubmissionListItemStudentPage({ return ( <> - + , - - {status ? ( - - ) : ( - - )} - + + + {status ? ( + + ) : ( + + )} + + ]}/> diff --git a/frontend/frontend/src/components/SubmissionListItemTeacherPage.tsx b/frontend/frontend/src/components/SubmissionListItemTeacherPage.tsx index 2904972e..cfaa2dc4 100644 --- a/frontend/frontend/src/components/SubmissionListItemTeacherPage.tsx +++ b/frontend/frontend/src/components/SubmissionListItemTeacherPage.tsx @@ -3,6 +3,7 @@ import { ListItemButton, ListItemIcon, ListItemText, + Box } from '@mui/material' import { useNavigate } from 'react-router-dom' import DownloadIcon from '@mui/icons-material/Download' @@ -127,13 +128,14 @@ export function SubmissionListItemTeacherPage({ return ( <> - + - , , , - - {!submitted?.status ? ( - - ) : ( - submitted !== undefined && ( - - ) - )} - , - -
- {submitted ? ( - + + + {!submitted?.status ? ( + ) : ( - + submitted !== undefined && ( + + ) )} -
-
+ +
, + + +
+ {submitted ? ( + + ) : ( + + )} +
+
+
]}>
diff --git a/frontend/frontend/src/pages/assignmentPage/AssignmentPage.tsx b/frontend/frontend/src/pages/assignmentPage/AssignmentPage.tsx index 9ad89bfc..4b0b5b06 100644 --- a/frontend/frontend/src/pages/assignmentPage/AssignmentPage.tsx +++ b/frontend/frontend/src/pages/assignmentPage/AssignmentPage.tsx @@ -395,7 +395,15 @@ export function AssignmentPage() { It shows metadata about the submissions and allows the teacher to download them. The metadata includes group number, submission time, score, and status. */} - + + {t('group')} @@ -414,12 +422,16 @@ export function AssignmentPage() { ]} /> - + + + > + + {loading ? ( [...Array(3)].map((_, index) => ( )) ) : ( - - {groups.map((group) => ( - - + <> + {groups.map((group,index) => ( + <> + {index != 0 ? : <>} - + ))} - + )} + + @@ -694,15 +708,15 @@ export function AssignmentPage() { {/* Submissions */} - + + {t('submission')} @@ -714,9 +728,12 @@ export function AssignmentPage() { Status ]}/> + + ( + .map((submission,index) => ( - + {index != 0 ? : <>} - - + {isStudent ? ( - <> + + />, + />, 0 ? submissions > 1 @@ -118,10 +101,10 @@ export function AssignmentListItemSubjectsPage({ t('submission') : t('no_submissions') } - /> + />, + <> {submissions > 0 ? ( ) : ( )} - + + ]}/> ) : ( <> {/* In case of the user being the teacher: */} + + />, + />, + />]}/> )} diff --git a/frontend/frontend/src/pages/subjectsPage/ProjectsView.tsx b/frontend/frontend/src/pages/subjectsPage/ProjectsView.tsx index 74e72937..09f1e01c 100644 --- a/frontend/frontend/src/pages/subjectsPage/ProjectsView.tsx +++ b/frontend/frontend/src/pages/subjectsPage/ProjectsView.tsx @@ -1,4 +1,4 @@ -import { Card, Divider } from '../../components/CustomComponents.tsx' +import {Card, Divider, EvenlySpacedRow} from '../../components/CustomComponents.tsx' import { Box, Skeleton, Typography } from '@mui/material' import List from '@mui/material/List' import { t } from 'i18next' @@ -155,42 +155,42 @@ export function ProjectsView({ aria-label={'courseHeader'} sx={{ backgroundColor: 'secondary.main', - margin: 0, - height: 50, - display: 'flex', - flexDirection: 'row', - justifyContent: 'space-between', + height: 20, padding: 3, }} > {!gebruiker.is_lesgever ? ( <> {/* Show the UI from the perspective of a student. */} + Project - + , Deadline - + , {t('submissions')} - + , Score + ]}/> ) : ( <> {/* Show the UI from the perspective of a teacher. */} + Project - + , Deadline - + , {t('edit')} - + ]} + /> )} @@ -199,17 +199,11 @@ export function ProjectsView({ sx={{ backgroundColor: 'background.default', height: 340, - display: 'flex', - flexDirection: 'column', - padding: 1, - borderRadius: 2, - paddingBottom: 0, }} > - {/* The list below will display the projects with their information */} - + {loading ? ( [...Array(3).keys()].map((index) => ( ( <> + - ))} @@ -305,7 +297,6 @@ export function ProjectsView({ - ) From c9617831c24ebedb34e2b10810d8e9387dff454b Mon Sep 17 00:00:00 2001 From: elias Date: Sun, 19 May 2024 10:51:42 +0200 Subject: [PATCH 05/24] knoppen assignmentpage fix --- .../src/components/CustomComponents.tsx | 4 +- .../pages/assignmentPage/AssignmentPage.tsx | 95 +++++++------------ .../src/pages/subjectsPage/SubjectsPage.tsx | 9 +- 3 files changed, 39 insertions(+), 69 deletions(-) diff --git a/frontend/frontend/src/components/CustomComponents.tsx b/frontend/frontend/src/components/CustomComponents.tsx index 8551f35d..848b299a 100644 --- a/frontend/frontend/src/components/CustomComponents.tsx +++ b/frontend/frontend/src/components/CustomComponents.tsx @@ -14,7 +14,7 @@ export const Button = ({ children, ...props }: any) => { disableElevation size="large" sx={{ - maxHeight: '35px', + maxHeight: '40px', backgroundColor: 'primary.main', textTransform: 'none', color: 'primary.contrastText', @@ -36,7 +36,7 @@ export const SecundaryButton = ({ children, ...props }: any) => { disableElevation size="large" sx={{ - maxHeight: '35px', + maxHeight: '40px', backgroundColor: 'secondary.main', textTransform: 'none', color: 'secondary.contrastText', diff --git a/frontend/frontend/src/pages/assignmentPage/AssignmentPage.tsx b/frontend/frontend/src/pages/assignmentPage/AssignmentPage.tsx index 4b0b5b06..9e8000f8 100644 --- a/frontend/frontend/src/pages/assignmentPage/AssignmentPage.tsx +++ b/frontend/frontend/src/pages/assignmentPage/AssignmentPage.tsx @@ -2,10 +2,10 @@ import { Header } from '../../components/Header.tsx' import FileUploadButton from '../../components/FileUploadButton.tsx' import { SubmissionListItemStudentPage } from '../../components/SubmissionListItemStudentPage.tsx' import { SubmissionListItemTeacherPage } from '../../components/SubmissionListItemTeacherPage.tsx' -import {Card, Button, Divider, EvenlySpacedRow} from '../../components/CustomComponents.tsx' +import {Card, Button, Divider, EvenlySpacedRow, SecundaryButton} from '../../components/CustomComponents.tsx' import { Box, - CircularProgress, + CircularProgress, Grid, List, Skeleton, Stack, @@ -840,65 +840,42 @@ export function AssignmentPage() { {/*Upload button, this is what the student will see. */} - - - { - - } - + + + + + + + - - - - - + + {t('submit')} + + + + + - + Date: Sun, 19 May 2024 11:11:44 +0200 Subject: [PATCH 06/24] updated group page --- .../src/pages/groupsPage/GroupsPage.tsx | 939 +++++++++--------- 1 file changed, 470 insertions(+), 469 deletions(-) diff --git a/frontend/frontend/src/pages/groupsPage/GroupsPage.tsx b/frontend/frontend/src/pages/groupsPage/GroupsPage.tsx index 7b6fbac6..d889c68d 100644 --- a/frontend/frontend/src/pages/groupsPage/GroupsPage.tsx +++ b/frontend/frontend/src/pages/groupsPage/GroupsPage.tsx @@ -1,5 +1,5 @@ import { Header } from '../../components/Header.tsx' -import { Button } from '../../components/CustomComponents.tsx' +import { Button, Card } from '../../components/CustomComponents.tsx' import { Box, Grid, @@ -7,14 +7,12 @@ import { MenuItem, Select, SelectChangeEvent, - CircularProgress, Skeleton, Stack, Table, TableBody, TableCell, TableContainer, - TableHead, TableRow, TextField, Tooltip, @@ -31,7 +29,6 @@ import { Add } from '@mui/icons-material' import ClearIcon from '@mui/icons-material/Clear' import SaveIcon from '@mui/icons-material/Save' import WarningPopup from '../../components/WarningPopup.tsx' -import { User } from '../subjectsPage/AddChangeSubjectPage.tsx' // group interface export interface Group { @@ -61,14 +58,12 @@ export function GroupsPage() { const [currentGroup, setCurrentGroup] = useState('') const [availableStudents, setAvailableStudents] = useState([]) const [projectName, setProjectName] = useState('') - const [user, setUser] = useState() // confirmation dialog state const [confirmOpen, setConfirmOpen] = useState(false) // state for correct loading of the page const [loading, setLoading] = useState(true) - const [userLoading, setUserLoading] = useState(true) // handle confirmation dialog const confirmSave = async () => { @@ -179,11 +174,7 @@ export function GroupsPage() { //get the current groups and group size from the backend useEffect(() => { async function fetchData() { - setUserLoading(true) setLoading(true) - const userResponse = await instance.get('/gebruikers/me/') - setUser(userResponse.data) - setUserLoading(false) // Get the student names await instance .get('/vakken/' + courseId) @@ -197,8 +188,8 @@ export function GroupsPage() { newStudentNames.set( student, response.data.first_name + - ' ' + - response.data.last_name + ' ' + + response.data.last_name ) }) .catch((error) => { @@ -212,12 +203,12 @@ export function GroupsPage() { newStudentNames.set( student, response.data.first_name + - ' ' + - response.data.last_name + ' ' + + response.data.last_name ) console.log( 'available names:' + - Array.from(newStudentNames.entries()) + Array.from(newStudentNames.entries()) ) }) } @@ -397,501 +388,511 @@ export function GroupsPage() { return ( <> - {/* Rendering different UI based on user role */} - {userLoading ? ( - +
+ - - -
- ) : ( - <> - {user?.is_lesgever ? ( - // Rendering UI for teacher - <> + -
+ + {t('groups')} + + + + + + {t('amount')} {t('members')}/ + {t('group')} + + + + {loading ? ( + + ) : ( + { + if ( + parseInt( + newValue.target + .value + ) < 1 + ) + return + handleGroupSizeChange( + parseInt( + newValue.target + .value + ) + ) + }} + variant="outlined" + sx={{ width: 80 }} + /> + )} + + + + {loading ? ( + + ) : ( + + )} + + + {t('students_choose')} + + {loading ? ( + + ) : ( + + )} + + +
+ + + *:not(:last-child)': { + marginRight: '40px', // Add right margin of 20 pixels + }, }} > - + - - {t('groups')} - - + - {t('amount')} {t('members')}/ {t('group')} - + {loading ? ( - ) : ( - { - if ( - parseInt( - newValue.target - .value - ) < 1 - ) - return - handleGroupSizeChange( - parseInt( - newValue.target - .value - ) - ) - }} - variant="outlined" - sx={{ width: 80 }} - /> - )} + ) : () + } - + + - {loading ? ( - - ) : ( - - )} - - - {t('students_choose')} - + {loading ? ( - + [...Array(3)].map( + (_, index) => ( + + ) + ) ) : ( - - )} - - - - - - - -
- - - - - {t('students')} - - - - - - {loading ? ( - [...Array(3)].map( - (_, index) => ( - + <> + {newGroups[ + parseInt( + currentGroup ) - ) - ) : ( - <> - {availableStudents.map( - (student) => ( - - - {studentNames.get( - student - ) === '' - ? student - : studentNames.get( - student - )} - = - newGroupSize - : true - } - onClick={() => { - assignStudent( - student, - parseInt( - currentGroup - ) - ) - }} - > - - - - - ) - )} - - )} - -
-
- - - - - - - {t('group')} - - {loading ? ( - - ) : ( - <> - - - )} - - - - - {loading ? ( - [...Array(3)].map( - (_, index) => ( - - ) - ) - ) : ( - <> - {newGroups[ - parseInt(currentGroup) - ] && - newGroups[ - parseInt( - currentGroup - ) - ].studenten.map( - (student) => ( - { + removeStudent( + student, + parseInt( + currentGroup + ) + ) + }} > - - {studentNames.get( + + + + + ) + )} + + )} + +
+
+
+ + + + {t('studenten')} + + + + + + {loading ? ( + [...Array(3)].map( + (_, index) => ( + + ) + ) + ) : ( + <> + + {chunkArray( + availableStudents, + Math.floor( + Math.sqrt( + availableStudents.length + ) + ) + 1 + ).map( + (students) => ( + + {students.map( + ( + student + ) => ( + { - removeStudent( - student, - parseInt( - currentGroup - ) - ) + } + > + - - - - - ) - )} - - )} - -
-
-
-
-
- - - - - - - - - - - {loading ? ( - - ) : ( - <> - - - - - )} - - - + {studentNames.get( + student + ) === + '' + ? student + : studentNames.get( + student + )} + = + newGroupSize + : true + } + onClick={() => { + assignStudent( + student, + parseInt( + currentGroup + ) + ) + }} + > + + + + + ) + )} + + ) + )} + + + )} + + + +
- {/* Warning popup for when the user wants to confirm the group changes */} - - - ):( - navigate('*') - )} - - )} - -)} +
+ + + + + + + + + + + {loading ? ( + + ) : ( + <> + + + + + )} + + + + + + {/* Warning popup for when the user wants to confirm the group changes */} + + + ) +} + +function chunkArray(arr: T[], chunkSize: number): T[][] { + let result: T[][] = [] + for (let i = 0; i < arr.length; i += chunkSize) { + let chunk: T[] = arr.slice(i, i + chunkSize) + result.push(chunk) + } + return result +} From 2d690292924efcfa84b1592f58f512845ee2c6a2 Mon Sep 17 00:00:00 2001 From: elias Date: Sun, 19 May 2024 13:56:19 +0200 Subject: [PATCH 07/24] opzoeken student werkt --- .../src/pages/groupsPage/GroupsPage.tsx | 80 +++++++++++++++---- package-lock.json | 6 ++ package.json | 1 + 3 files changed, 73 insertions(+), 14 deletions(-) diff --git a/frontend/frontend/src/pages/groupsPage/GroupsPage.tsx b/frontend/frontend/src/pages/groupsPage/GroupsPage.tsx index d889c68d..deee1d56 100644 --- a/frontend/frontend/src/pages/groupsPage/GroupsPage.tsx +++ b/frontend/frontend/src/pages/groupsPage/GroupsPage.tsx @@ -1,6 +1,7 @@ import { Header } from '../../components/Header.tsx' import { Button, Card } from '../../components/CustomComponents.tsx' import { + Autocomplete, Box, Grid, IconButton, @@ -135,6 +136,7 @@ export function GroupsPage() { const handleGroupSizeChange = (newValue: number) => { setNewGroupSize(newValue) setAvailableStudents(() => Array.from(studentNames.keys())) + setFilteredStudents(availableStudents); setCurrentGroup('0') setNewGroups(() => { const newGroups = [] @@ -156,6 +158,7 @@ export function GroupsPage() { .get('/vakken/' + courseId) .then((response) => { setAvailableStudents(response.data.studenten) + setFilteredStudents(availableStudents) }) .catch((error) => { console.error(error) @@ -283,12 +286,14 @@ export function GroupsPage() { ) ) ) + setFilteredStudents(availableStudents); }, [newGroups, studentNames]) // Create new groups when the group size changes useEffect(() => { if (newGroups.length === 0) { setAvailableStudents(() => Array.from(studentNames.keys())) + setFilteredStudents(availableStudents); setCurrentGroup('0') setNewGroups(() => { const newGroups = [] @@ -346,6 +351,7 @@ export function GroupsPage() { (student) => student !== studentId ) setAvailableStudents(updatedAvailableStudents) + setFilteredStudents(availableStudents); // Then, create a new copy of the newGroups array with the updated group const updatedNewGroups = newGroups.map((group, index) => { if (index === groupId) { @@ -386,6 +392,26 @@ export function GroupsPage() { setNewGroups(updatedNewGroups) } + const [filteredStudents, setFilteredStudents] = useState(availableStudents); + + // for filtering students + const handleAutocompleteChange = (_, value) => { + if(value){ + setFilteredStudents([value]) + } + }; + + const resetAutocompleteChange = () => { + setFilteredStudents(availableStudents); + } + + const filterOptions = (_,{ inputValue }) => { + const filtered = availableStudents.filter((option) => { + const label = studentNames.get(option); + return label?.toLowerCase().startsWith(inputValue.toLowerCase()); + }); + return filtered; + }; return ( <> - - - {t('studenten')} - + + + + + {t('studenten')} + + + + + + {loading ? ( + + ) : ( + studentNames.get(student)} + onChange={handleAutocompleteChange} + filterOptions={filterOptions} + renderInput={(student) => } + />)} + + + + {chunkArray( - availableStudents, - Math.floor( - Math.sqrt( - availableStudents.length - ) - ) + 1 + filteredStudents, + Math.ceil( + Math.sqrt(filteredStudents.length) + ) ).map( (students) => ( @@ -792,6 +843,7 @@ export function GroupsPage() { currentGroup ) ) + resetAutocompleteChange() }} > diff --git a/package-lock.json b/package-lock.json index de269d44..1b8a0d3d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.0", "@mui/material": "^5.15.12", + "lodash": "^4.17.21", "react-datepicker": "^6.2.0" } }, @@ -768,6 +769,11 @@ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", diff --git a/package.json b/package.json index dde0d41f..f4a11f7a 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.0", "@mui/material": "^5.15.12", + "lodash": "^4.17.21", "react-datepicker": "^6.2.0" } } From 2dcb9222ead0ef5f2f222a7974bea1d18cfa1041 Mon Sep 17 00:00:00 2001 From: Ben De Meurichy Date: Sun, 19 May 2024 15:46:40 +0200 Subject: [PATCH 08/24] type errors weggekregen --- .../src/pages/groupsPage/GroupsPage.tsx | 188 ++++++++++-------- 1 file changed, 109 insertions(+), 79 deletions(-) diff --git a/frontend/frontend/src/pages/groupsPage/GroupsPage.tsx b/frontend/frontend/src/pages/groupsPage/GroupsPage.tsx index deee1d56..38707a4d 100644 --- a/frontend/frontend/src/pages/groupsPage/GroupsPage.tsx +++ b/frontend/frontend/src/pages/groupsPage/GroupsPage.tsx @@ -136,7 +136,7 @@ export function GroupsPage() { const handleGroupSizeChange = (newValue: number) => { setNewGroupSize(newValue) setAvailableStudents(() => Array.from(studentNames.keys())) - setFilteredStudents(availableStudents); + setFilteredStudents(availableStudents) setCurrentGroup('0') setNewGroups(() => { const newGroups = [] @@ -191,8 +191,8 @@ export function GroupsPage() { newStudentNames.set( student, response.data.first_name + - ' ' + - response.data.last_name + ' ' + + response.data.last_name ) }) .catch((error) => { @@ -206,12 +206,12 @@ export function GroupsPage() { newStudentNames.set( student, response.data.first_name + - ' ' + - response.data.last_name + ' ' + + response.data.last_name ) console.log( 'available names:' + - Array.from(newStudentNames.entries()) + Array.from(newStudentNames.entries()) ) }) } @@ -286,14 +286,14 @@ export function GroupsPage() { ) ) ) - setFilteredStudents(availableStudents); + setFilteredStudents(availableStudents) }, [newGroups, studentNames]) // Create new groups when the group size changes useEffect(() => { if (newGroups.length === 0) { setAvailableStudents(() => Array.from(studentNames.keys())) - setFilteredStudents(availableStudents); + setFilteredStudents(availableStudents) setCurrentGroup('0') setNewGroups(() => { const newGroups = [] @@ -351,7 +351,7 @@ export function GroupsPage() { (student) => student !== studentId ) setAvailableStudents(updatedAvailableStudents) - setFilteredStudents(availableStudents); + setFilteredStudents(availableStudents) // Then, create a new copy of the newGroups array with the updated group const updatedNewGroups = newGroups.map((group, index) => { if (index === groupId) { @@ -392,26 +392,28 @@ export function GroupsPage() { setNewGroups(updatedNewGroups) } - const [filteredStudents, setFilteredStudents] = useState(availableStudents); + const [filteredStudents, setFilteredStudents] = useState(availableStudents) // for filtering students - const handleAutocompleteChange = (_, value) => { - if(value){ + const handleAutocompleteChange = (_: unknown, value: number | null) => { + if (value) { setFilteredStudents([value]) } - }; + } const resetAutocompleteChange = () => { - setFilteredStudents(availableStudents); + setFilteredStudents(availableStudents) } - const filterOptions = (_,{ inputValue }) => { - const filtered = availableStudents.filter((option) => { - const label = studentNames.get(option); - return label?.toLowerCase().startsWith(inputValue.toLowerCase()); - }); - return filtered; - }; + const filterOptions = ( + _: unknown, + { inputValue }: { inputValue: string } + ) => { + return availableStudents.filter((option) => { + const label = studentNames.get(option) + return label?.toLowerCase().startsWith(inputValue.toLowerCase()) + }) + } return ( <> - ) : ( + {newGroups.map( + (_, index) => ( + + {t( 'group' ) + - (index + - 1)} - - ) - )} - ) - } + (index + + 1)} + + ) + )} + + )} @@ -662,15 +665,15 @@ export function GroupsPage() { ) : ( <> {newGroups[ - parseInt( - currentGroup - ) - ] && + parseInt( + currentGroup + ) + ] && newGroups[ parseInt( currentGroup ) - ].studenten.map( + ].studenten.map( (student) => ( - + {t('studenten')} - + {loading ? ( ) : ( studentNames.get(student)} - onChange={handleAutocompleteChange} - filterOptions={filterOptions} - renderInput={(student) => } - />)} + options={ + availableStudents + } + getOptionLabel={( + student + ) => { + const name = + studentNames.get( + student + ) + return name != + null + ? name + : '' // This checks for both null and undefined + }} + onChange={ + handleAutocompleteChange + } + filterOptions={ + filterOptions + } + renderInput={( + student + ) => ( + + )} + /> + )} @@ -757,9 +785,9 @@ export function GroupsPage() {
{loading ? ( @@ -784,7 +812,9 @@ export function GroupsPage() { {chunkArray( filteredStudents, Math.ceil( - Math.sqrt(filteredStudents.length) + Math.sqrt( + filteredStudents.length + ) ) ).map( (students) => ( @@ -817,23 +847,23 @@ export function GroupsPage() { '' ? student : studentNames.get( - student - )} + student + )} = - newGroupSize + parseInt( + currentGroup + ) + ] + .studenten + .length >= + newGroupSize : true } onClick={() => { @@ -941,9 +971,9 @@ export function GroupsPage() { } function chunkArray(arr: T[], chunkSize: number): T[][] { - let result: T[][] = [] + const result: T[][] = [] for (let i = 0; i < arr.length; i += chunkSize) { - let chunk: T[] = arr.slice(i, i + chunkSize) + const chunk: T[] = arr.slice(i, i + chunkSize) result.push(chunk) } return result From af5db55c007194bf76fd0b36d38c2a565474076a Mon Sep 17 00:00:00 2001 From: elias Date: Sun, 19 May 2024 16:36:07 +0200 Subject: [PATCH 09/24] made clickable area of listitems for assigment and subject page smaller --- .../frontend/src/components/SubmissionListItemStudentPage.tsx | 4 +++- .../frontend/src/components/SubmissionListItemTeacherPage.tsx | 2 +- .../src/pages/subjectsPage/AssignmentListItemSubjectsPage.tsx | 4 +++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/frontend/frontend/src/components/SubmissionListItemStudentPage.tsx b/frontend/frontend/src/components/SubmissionListItemStudentPage.tsx index 68840f6f..f1d8ff2e 100644 --- a/frontend/frontend/src/components/SubmissionListItemStudentPage.tsx +++ b/frontend/frontend/src/components/SubmissionListItemStudentPage.tsx @@ -52,7 +52,9 @@ export function SubmissionListItemStudentPage({ return ( <> - + - - + {isStudent ? ( Date: Sun, 19 May 2024 16:38:38 +0200 Subject: [PATCH 10/24] typo in secondaryButton --- frontend/frontend/src/components/CustomComponents.tsx | 4 ++-- .../frontend/src/pages/assignmentPage/AssignmentPage.tsx | 6 +++--- frontend/frontend/src/pages/subjectsPage/StudentPopUp.tsx | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/frontend/frontend/src/components/CustomComponents.tsx b/frontend/frontend/src/components/CustomComponents.tsx index 848b299a..61dbd4cb 100644 --- a/frontend/frontend/src/components/CustomComponents.tsx +++ b/frontend/frontend/src/components/CustomComponents.tsx @@ -1,4 +1,4 @@ -import { darken,lighten } from '@mui/system'; +import { darken } from '@mui/system'; import { Button as BaseButton, Card as BaseCard, @@ -29,7 +29,7 @@ export const Button = ({ children, ...props }: any) => { ) } -export const SecundaryButton = ({ children, ...props }: any) => { +export const SecondaryButton = ({ children, ...props }: any) => { return ( - {t('submit')} - + diff --git a/frontend/frontend/src/pages/subjectsPage/StudentPopUp.tsx b/frontend/frontend/src/pages/subjectsPage/StudentPopUp.tsx index 7628bb67..6f7d73ee 100644 --- a/frontend/frontend/src/pages/subjectsPage/StudentPopUp.tsx +++ b/frontend/frontend/src/pages/subjectsPage/StudentPopUp.tsx @@ -1,7 +1,7 @@ import { User } from './AddChangeSubjectPage' import * as React from 'react' import { IconButton, List, ListItem, ListItemText, Typography } from '@mui/material' -import {Button, SecundaryButton} from '../../components/CustomComponents' +import {Button, SecondaryButton} from '../../components/CustomComponents' import Dialog from '@mui/material/Dialog' import DialogTitle from '@mui/material/DialogTitle' import CloseIcon from '@mui/icons-material/Close' @@ -23,13 +23,13 @@ export default function StudentPopUp({ students, text }: StudentPopUpProps) { return ( <> {/* Students Button */} - { setOpen(true) }} > {t(text)} - + {/* Students Dialog */} Date: Sun, 19 May 2024 16:48:47 +0200 Subject: [PATCH 11/24] started removing anies --- .../src/components/CustomComponents.tsx | 9 ++++++-- .../pages/assignmentPage/AssignmentPage.tsx | 22 +++++-------------- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/frontend/frontend/src/components/CustomComponents.tsx b/frontend/frontend/src/components/CustomComponents.tsx index 61dbd4cb..36225589 100644 --- a/frontend/frontend/src/components/CustomComponents.tsx +++ b/frontend/frontend/src/components/CustomComponents.tsx @@ -3,9 +3,10 @@ import { Button as BaseButton, Card as BaseCard, Divider as BaseDivider, - Box + Box, ButtonProps } from '@mui/material' import theme from '../Theme.ts' +import {ReactNode} from "react"; export const Button = ({ children, ...props }: any) => { return ( @@ -29,7 +30,11 @@ export const Button = ({ children, ...props }: any) => { ) } -export const SecondaryButton = ({ children, ...props }: any) => { +interface SecondaryButtonProps extends ButtonProps { + children: ReactNode; +} + +export const SecondaryButton = ({ children, ...props }: SecondaryButtonProps) => { return ( {submissions.length > 0 && ( - + )} - + {loading ? ( ) : ( - + {t('adjust_scores')} + )} From 773c33493a39c88a5541082151765825a766e071 Mon Sep 17 00:00:00 2001 From: elias Date: Sun, 19 May 2024 16:54:29 +0200 Subject: [PATCH 12/24] any gone now --- .../src/components/CustomComponents.tsx | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/frontend/frontend/src/components/CustomComponents.tsx b/frontend/frontend/src/components/CustomComponents.tsx index 36225589..8a8724c3 100644 --- a/frontend/frontend/src/components/CustomComponents.tsx +++ b/frontend/frontend/src/components/CustomComponents.tsx @@ -3,12 +3,16 @@ import { Button as BaseButton, Card as BaseCard, Divider as BaseDivider, - Box, ButtonProps + Box, ButtonProps, CardProps, DividerProps } from '@mui/material' import theme from '../Theme.ts' import {ReactNode} from "react"; -export const Button = ({ children, ...props }: any) => { +interface PrimaryButtonProps extends ButtonProps { + children: ReactNode; +} + +export const Button = ({ children, ...props }: PrimaryButtonProps) => { return ( ) } -export const Card = ({ children, ...props }: any) => { +interface CustomCardProps extends CardProps { + children: ReactNode; +} + +export const Card = ({ children, ...props }: CustomCardProps) => { return ( { ) } -export const Divider = ({ children, ...props }: any) => { +interface CustomDividerProps extends DividerProps { + children?: ReactNode; +} + +export const Divider = ({ children, ...props }: CustomCardProps) => { return ( { ) } -export const EvenlySpacedRow = ({items}) => { +interface EvenlySpacedRowProps { + items: ReactNode[]; +} + +export const EvenlySpacedRow = ({items} : EvenlySpacedRowProps) => { return ( Date: Sun, 19 May 2024 16:56:03 +0200 Subject: [PATCH 13/24] inladen studenten bij groepen is niet meer onacceptabel traag --- .../src/pages/groupsPage/GroupsPage.tsx | 53 +++++++------------ 1 file changed, 19 insertions(+), 34 deletions(-) diff --git a/frontend/frontend/src/pages/groupsPage/GroupsPage.tsx b/frontend/frontend/src/pages/groupsPage/GroupsPage.tsx index 38707a4d..003057c6 100644 --- a/frontend/frontend/src/pages/groupsPage/GroupsPage.tsx +++ b/frontend/frontend/src/pages/groupsPage/GroupsPage.tsx @@ -30,6 +30,8 @@ import { Add } from '@mui/icons-material' import ClearIcon from '@mui/icons-material/Clear' import SaveIcon from '@mui/icons-material/Save' import WarningPopup from '../../components/WarningPopup.tsx' +import axios, { AxiosResponse } from 'axios' +import { User } from '../subjectsPage/AddChangeSubjectPage.tsx' // group interface export interface Group { @@ -182,39 +184,21 @@ export function GroupsPage() { await instance .get('/vakken/' + courseId) .then(async (response) => { + // This function fetches the names of the students in parallel const newStudentNames = new Map() - - for (const student of response.data.studenten) { - await instance - .get('/gebruikers/' + student) - .then((response) => { - newStudentNames.set( - student, - response.data.first_name + - ' ' + - response.data.last_name - ) - }) - .catch((error) => { - console.log(error) - }) - } - for (const student of response.data.studenten) { - await instance - .get('/gebruikers/' + student) - .then((response) => { - newStudentNames.set( - student, - response.data.first_name + - ' ' + - response.data.last_name - ) - console.log( - 'available names:' + - Array.from(newStudentNames.entries()) - ) - }) - } + const studentPromises: Promise>[] = + response.data.studenten.map((id: number) => + instance.get('/gebruikers/' + id) + ) + const studentResponses = await axios.all(studentPromises) + + studentResponses.forEach((response) => { + const student: User = response.data + newStudentNames.set( + student.user, + student.first_name + ' ' + student.last_name + ) + }) setStudentNames(() => newStudentNames) }) @@ -275,7 +259,7 @@ export function GroupsPage() { .catch((error) => { console.log(error) }) - }, [assignmentId, courseId, newGroupSize, studentNames.size]) + }, [assignmentId, courseId]) useEffect(() => { setAvailableStudents(() => @@ -287,7 +271,7 @@ export function GroupsPage() { ) ) setFilteredStudents(availableStudents) - }, [newGroups, studentNames]) + }, [availableStudents, newGroups, studentNames]) // Create new groups when the group size changes useEffect(() => { @@ -312,6 +296,7 @@ export function GroupsPage() { } }, [ assignmentId, + availableStudents, availableStudents.length, newGroupSize, newGroups.length, From 98ab6377b0a268bd6b9fc0da6af8e288c137ec67 Mon Sep 17 00:00:00 2001 From: elias Date: Sun, 19 May 2024 16:58:16 +0200 Subject: [PATCH 14/24] ran formatting and removed unused imports --- .../src/components/CustomComponents.tsx | 65 +- .../src/components/DeadlineCalendar.tsx | 62 +- .../SubmissionListItemStudentPage.tsx | 61 +- .../SubmissionListItemTeacherPage.tsx | 149 ++- .../AddChangeAssignmentPage.tsx | 1139 +++++++++-------- .../pages/assignmentPage/AssignmentPage.tsx | 339 +++-- .../src/pages/groupsPage/ChooseGroup.tsx | 784 ++++++++---- .../src/pages/groupsPage/GroupsPage.tsx | 177 +-- .../pages/scoresPage/ProjectScoresPage.tsx | 331 ++--- .../pages/scoresPage/StudentScoreListItem.tsx | 48 +- .../subjectsPage/AddChangeSubjectPage.tsx | 323 ++--- .../AssignmentListItemSubjectsPage.tsx | 129 +- .../src/pages/subjectsPage/ProjectsView.tsx | 133 +- .../src/pages/subjectsPage/StudentPopUp.tsx | 32 +- .../src/pages/subjectsPage/SubjectsPage.tsx | 57 +- .../pages/submissionPage/SubmissionPage.tsx | 13 +- frontend/frontend/src/routes.tsx | 2 +- 17 files changed, 2221 insertions(+), 1623 deletions(-) diff --git a/frontend/frontend/src/components/CustomComponents.tsx b/frontend/frontend/src/components/CustomComponents.tsx index 8a8724c3..01599c77 100644 --- a/frontend/frontend/src/components/CustomComponents.tsx +++ b/frontend/frontend/src/components/CustomComponents.tsx @@ -1,15 +1,18 @@ -import { darken } from '@mui/system'; +import { darken } from '@mui/system' import { Button as BaseButton, Card as BaseCard, Divider as BaseDivider, - Box, ButtonProps, CardProps, DividerProps + Box, + ButtonProps, + CardProps, + DividerProps, } from '@mui/material' import theme from '../Theme.ts' -import {ReactNode} from "react"; +import { ReactNode } from 'react' interface PrimaryButtonProps extends ButtonProps { - children: ReactNode; + children: ReactNode } export const Button = ({ children, ...props }: PrimaryButtonProps) => { @@ -24,7 +27,7 @@ export const Button = ({ children, ...props }: PrimaryButtonProps) => { textTransform: 'none', color: 'primary.contrastText', '&:hover': { - backgroundColor: darken(theme.palette.primary.main,0.5), + backgroundColor: darken(theme.palette.primary.main, 0.5), }, }} {...props} @@ -35,10 +38,13 @@ export const Button = ({ children, ...props }: PrimaryButtonProps) => { } interface SecondaryButtonProps extends ButtonProps { - children: ReactNode; + children: ReactNode } -export const SecondaryButton = ({ children, ...props }: SecondaryButtonProps) => { +export const SecondaryButton = ({ + children, + ...props +}: SecondaryButtonProps) => { return ( textTransform: 'none', color: 'secondary.contrastText', '&:hover': { - backgroundColor: darken(theme.palette.secondary.main,0.2), + backgroundColor: darken(theme.palette.secondary.main, 0.2), }, }} {...props} @@ -61,7 +67,7 @@ export const SecondaryButton = ({ children, ...props }: SecondaryButtonProps) => } interface CustomCardProps extends CardProps { - children: ReactNode; + children: ReactNode } export const Card = ({ children, ...props }: CustomCardProps) => { @@ -81,7 +87,7 @@ export const Card = ({ children, ...props }: CustomCardProps) => { } interface CustomDividerProps extends DividerProps { - children?: ReactNode; + children?: ReactNode } export const Divider = ({ children, ...props }: CustomCardProps) => { @@ -99,36 +105,33 @@ export const Divider = ({ children, ...props }: CustomCardProps) => { } interface EvenlySpacedRowProps { - items: ReactNode[]; + items: ReactNode[] } -export const EvenlySpacedRow = ({items} : EvenlySpacedRowProps) => { +export const EvenlySpacedRow = ({ items }: EvenlySpacedRowProps) => { return ( - + {items.map((item, index) => ( - - - {item} - + width={ + index == 0 || index == items.length - 1 + ? 50 / items.length + '%' + : (100 - 100 / items.length) / (items.length - 2) + + '%' + } + sx={{ + //border: '1px solid red', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + }} + > + {item} ))} - + ) } - - export default { Button, Card, Divider, EvenlySpacedRow } diff --git a/frontend/frontend/src/components/DeadlineCalendar.tsx b/frontend/frontend/src/components/DeadlineCalendar.tsx index 8772029d..bc87c398 100644 --- a/frontend/frontend/src/components/DeadlineCalendar.tsx +++ b/frontend/frontend/src/components/DeadlineCalendar.tsx @@ -5,7 +5,17 @@ import { PickersDayProps, } from '@mui/x-date-pickers' import dayjs, { Dayjs } from 'dayjs' -import { Badge, SxProps, Stack, Typography, Box, List, ListItem, ListItemButton, ListItemText } from '@mui/material' +import { + Badge, + SxProps, + Stack, + Typography, + Box, + List, + ListItem, + ListItemButton, + ListItemText, +} from '@mui/material' import { useEffect, useRef, useState } from 'react' import AssignmentIcon from '@mui/icons-material/Assignment' import { useNavigate } from 'react-router-dom' @@ -95,22 +105,26 @@ function DeadlineMenu({ assignments, selectedDay }: DeadlineMenuProps) { {assignments - .filter((assignment: project) => - dayjs(assignment.deadline).isSame(selectedDay, 'day') - ).map((assignment: project) => - - handleProjectClick(assignment.vak, assignment.project_id)} - > - - - - )} + .filter((assignment: project) => + dayjs(assignment.deadline).isSame(selectedDay, 'day') + ) + .map((assignment: project) => ( + + + handleProjectClick( + assignment.vak, + assignment.project_id + ) + } + > + + + + ))} ) @@ -121,7 +135,10 @@ interface DeadlineCalendarProps { assignments: project[] } -export function DeadlineCalendar({ deadlines, assignments }: DeadlineCalendarProps) { +export function DeadlineCalendar({ + deadlines, + assignments, +}: DeadlineCalendarProps) { const requestAbortController = useRef(null) const [isLoading, setIsLoading] = useState(false) const [highlightedDays, setHighlightedDays] = useState([]) @@ -173,9 +190,7 @@ export function DeadlineCalendar({ deadlines, assignments }: DeadlineCalendarPro return ( <> - + {/*Calendar*/} - + ) diff --git a/frontend/frontend/src/components/SubmissionListItemStudentPage.tsx b/frontend/frontend/src/components/SubmissionListItemStudentPage.tsx index f1d8ff2e..4e0f80cf 100644 --- a/frontend/frontend/src/components/SubmissionListItemStudentPage.tsx +++ b/frontend/frontend/src/components/SubmissionListItemStudentPage.tsx @@ -1,4 +1,4 @@ -import { EvenlySpacedRow} from "./CustomComponents.tsx"; +import { EvenlySpacedRow } from './CustomComponents.tsx' import { ListItem, ListItemButton, @@ -53,33 +53,38 @@ export function SubmissionListItemStudentPage({ <> - , - , - - - {status ? ( - - ) : ( - - )} - - - ]}/> + sx={{ maxHeight: '30px' }} + onClick={handleSubmissionClick} + > + , + , + + + {status ? ( + + ) : ( + + )} + + , + ]} + /> diff --git a/frontend/frontend/src/components/SubmissionListItemTeacherPage.tsx b/frontend/frontend/src/components/SubmissionListItemTeacherPage.tsx index 692d56e0..4ba9654f 100644 --- a/frontend/frontend/src/components/SubmissionListItemTeacherPage.tsx +++ b/frontend/frontend/src/components/SubmissionListItemTeacherPage.tsx @@ -3,7 +3,7 @@ import { ListItemButton, ListItemIcon, ListItemText, - Box + Box, } from '@mui/material' import { useNavigate } from 'react-router-dom' import DownloadIcon from '@mui/icons-material/Download' @@ -14,7 +14,7 @@ import instance from '../axiosConfig' import { Submission } from '../pages/submissionPage/SubmissionPage.tsx' import { t } from 'i18next' import dayjs from 'dayjs' -import {EvenlySpacedRow} from "./CustomComponents.tsx"; +import { EvenlySpacedRow } from './CustomComponents.tsx' interface SubmissionListItemTeacherPageProps { relative_group_id: string @@ -63,17 +63,21 @@ export function SubmissionListItemTeacherPage({ submissionsResponse.data[ submissionsResponse.data.length - 1 ] - const lastSubmissionResponse = await instance.get(`indieningen/${lastSubmission.indiening_id}/`) + const lastSubmissionResponse = await instance.get( + `indieningen/${lastSubmission.indiening_id}/` + ) //Get the submission file const newSubmission: Submission = lastSubmissionResponse.data - newSubmission.filename = lastSubmissionResponse.data.bestand.replace( - /^.*[\\/]/, - '' - ) + newSubmission.filename = + lastSubmissionResponse.data.bestand.replace(/^.*[\\/]/, '') newSubmission.bestand = await instance - .get(`/indieningen/${lastSubmission.indiening_id}/indiening_bestand`, { - responseType: 'blob', - }).then((res) => { + .get( + `/indieningen/${lastSubmission.indiening_id}/indiening_bestand`, + { + responseType: 'blob', + } + ) + .then((res) => { let filename = 'indiening.zip' if (newSubmission.filename) { filename = newSubmission.filename @@ -107,9 +111,7 @@ export function SubmissionListItemTeacherPage({ const url = window.URL.createObjectURL(submitted?.bestand) const a = document.createElement('a') a.href = url - a.download = submitted.filename - ? submitted.filename - : 'opgave.zip' + a.download = submitted.filename ? submitted.filename : 'opgave.zip' document.body.appendChild(a) a.click() a.remove() @@ -128,70 +130,75 @@ export function SubmissionListItemTeacherPage({ return ( <> - - + , - , - , - - - {!submitted?.status ? ( - - ) : ( - submitted !== undefined && ( - - ) - )} - - , - - -
- {submitted ? ( - , + , + , + + + {!submitted?.status ? ( + ) : ( - + submitted !== undefined && ( + + ) )} -
-
-
- ]}> -
+ +
, + + +
+ {submitted ? ( + + ) : ( + + )} +
+
+
, + ]} + >
diff --git a/frontend/frontend/src/pages/addChangeAssignmentPage/AddChangeAssignmentPage.tsx b/frontend/frontend/src/pages/addChangeAssignmentPage/AddChangeAssignmentPage.tsx index 33d50574..5ed43e36 100644 --- a/frontend/frontend/src/pages/addChangeAssignmentPage/AddChangeAssignmentPage.tsx +++ b/frontend/frontend/src/pages/addChangeAssignmentPage/AddChangeAssignmentPage.tsx @@ -191,15 +191,11 @@ export function AddChangeAssignmentPage() { setVisible(assignment.zichtbaar) if (assignment.deadline !== null) { - setDueDate( - dayjs(assignment.deadline) - ) + setDueDate(dayjs(assignment.deadline)) console.log('deadline' + assignment.deadline) } if (assignment.extra_deadline !== null) { - setExtraDueDate( - dayjs(assignment.extra_deadline) - ) + setExtraDueDate(dayjs(assignment.extra_deadline)) console.log( 'extra deadline' + assignment.extra_deadline ) @@ -472,529 +468,622 @@ export function AddChangeAssignmentPage() { <> {user?.is_lesgever ? ( // Rendering UI for teacher - <> - {/* Stack container for layout */} - - {/*very ugly but it works functionally*/} - {loading ? ( -
- ) : ( -
- )} - {/* Form for submitting assignment */} - - - - {/* Here the user gets to specify the assignment name */} - - {t('assignmentName')} - - {loading ? ( - - ) : ( - - setTitle(event.target.value) - } - /> - )} - - {/* File Upload button */} - - {loading ? ( - { - console.log('loading') - }} - fileTypes={['.pdf', '.zip']} - path={new File([], 'loading...')} - /> - ) : ( - - )} - - - {/* Deadline section. + <> + {/* Stack container for layout */} + + {/*very ugly but it works functionally*/} + {loading ? ( +
+ ) : ( +
+ )} + {/* Form for submitting assignment */} + + + + {/* Here the user gets to specify the assignment name */} + + {t('assignmentName')} + + {loading ? ( + + ) : ( + + setTitle( + event.target.value + ) + } + /> + )} + + {/* File Upload button */} + + {loading ? ( + { + console.log('loading') + }} + fileTypes={['.pdf', '.zip']} + path={ + new File( + [], + 'loading...' + ) + } + /> + ) : ( + + )} + + + {/* Deadline section. There is both the normal deadline, and an extra deadline in case people need more time. */} - - - {/* This section renders the normal deadline. */} - - Deadline: - - {loading ? ( - - ) : ( - - - SetDeadlineError(newError) - } - slotProps={{ - field: { - clearable: true, - onClear: () => setCleared(true), - }, - textField: { - helperText: errorMessage, - }, - }} - onChange={(newValue) => - setDueDate(newValue) - } - /> - - )} - - - {/* This section renders the extra deadline. */} - - Extra Deadline: - - {loading ? ( - - ) : ( - - setCleared(true), - }, - textField: { - error: deadlineCheckError, - helperText: deadlineCheckError - ? t('deadlineCheck') - : '', - }, + - setExtraDueDate(newValue) - } - /> - - )} - - - {/* Description section */} - - - - {t('description')} - - {loading ? ( - - ) : ( - - setDescription(event.target.value) - } - fullWidth - error={assignmentErrors.description} - // Show an error message if the description is not filled in. - helperText={ - assignmentErrors.description - ? t('descriptionName') + - ' ' + - t('is_required') - : '' - } - sx={{ - overflowY: 'auto', - maxHeight: '25svh', - }} - /> - )} - - - {/* Restrictions section */} - - - - {t('restrictions')} - - - {/*This list will render the restrictions that are added to the assignment.*/} - - {loading ? ( - - ) : ( - <> - {restrictions.map( - (restriction, index) => { - return ( - - - - ) - } - )} - - )} - - - - - - setRestrictions(newRestrictions) - } - > - - - - - {/* Main actions section */} - - - - {visible ? ( - setVisible(!visible)} + gap={5} > - - - ) : ( - setVisible(!visible)} + + {/* This section renders the normal deadline. */} + + Deadline: + + {loading ? ( + + ) : ( + + + SetDeadlineError( + newError + ) + } + slotProps={{ + field: { + clearable: true, + onClear: () => + setCleared( + true + ), + }, + textField: { + helperText: + errorMessage, + }, + }} + onChange={(newValue) => + setDueDate(newValue) + } + /> + + )} + + + {/* This section renders the extra deadline. */} + + Extra Deadline: + + {loading ? ( + + ) : ( + + + setCleared( + true + ), + }, + textField: { + error: deadlineCheckError, + helperText: + deadlineCheckError + ? t( + 'deadlineCheck' + ) + : '', + }, + }} + onChange={(newValue) => + setExtraDueDate( + newValue + ) + } + /> + + )} + + + {/* Description section */} + + + + {t('description')} + + {loading ? ( + + ) : ( + + setDescription( + event.target.value + ) + } + fullWidth + error={ + assignmentErrors.description + } + // Show an error message if the description is not filled in. + helperText={ + assignmentErrors.description + ? t( + 'descriptionName' + ) + + ' ' + + t('is_required') + : '' + } + sx={{ + overflowY: 'auto', + maxHeight: '25svh', + }} + /> + )} + + + {/* Restrictions section */} + - - - )} - - + + {t('restrictions')} + + + {/*This list will render the restrictions that are added to the assignment.*/} + + {loading ? ( + + ) : ( + <> + {restrictions.map( + ( + restriction, + index + ) => { + return ( + + + + ) + } + )} + + )} + + + + + + setRestrictions( + newRestrictions + ) + } + > + + + + + {/* Main actions section */} + - - - - - {/* This section allows the teacher to set the maximum score for the assignment.*/} - - - Max Score - - {loading ? ( - - ) : ( - { - if (event.target.value !== '') { - const newScore = Math.max( - parseInt( - event.target.value - ), - 0 - ) - SetMaxScore - ? SetMaxScore(newScore) - : undefined - } else { - SetMaxScore - ? SetMaxScore( - parseInt( - event.target.value - ) - ) - : undefined - } - }} - /> - )} - - - {/* Submit and Cancel buttons */} - - - setCancelConfirmation(true)} - sx={{ - backgroundColor: 'secondary.main', - borderRadius: 2, - }} - > - - - - - - - - - - - - - {/* Popup for adding restrictions */} - - {/* Confirmation popup for deleting project */} - - - {/* Confirmation popup for saving project */} - - {/* Confirmation popup for canceling changes*/} - - + + + {visible ? ( + + setVisible(!visible) + } + > + + + ) : ( + + setVisible(!visible) + } + > + + + )} + + + + + + + {/* This section allows the teacher to set the maximum score for the assignment.*/} + + + Max Score + + {loading ? ( + + ) : ( + { + if ( + event.target + .value !== + '' + ) { + const newScore = + Math.max( + parseInt( + event + .target + .value + ), + 0 + ) + SetMaxScore + ? SetMaxScore( + newScore + ) + : undefined + } else { + SetMaxScore + ? SetMaxScore( + parseInt( + event + .target + .value + ) + ) + : undefined + } + }} + /> + )} + + + {/* Submit and Cancel buttons */} + + + + setCancelConfirmation( + true + ) + } + sx={{ + backgroundColor: + 'secondary.main', + borderRadius: 2, + }} + > + + + + + + + + + + + + + {/* Popup for adding restrictions */} + + {/* Confirmation popup for deleting project */} + + + {/* Confirmation popup for saving project */} + + {/* Confirmation popup for canceling changes*/} + + + + ) : ( + navigate('*') + )} + + )} - ):( - navigate('*') - )} - -)} - -)} + ) +} diff --git a/frontend/frontend/src/pages/assignmentPage/AssignmentPage.tsx b/frontend/frontend/src/pages/assignmentPage/AssignmentPage.tsx index 7487488f..ebc1759f 100644 --- a/frontend/frontend/src/pages/assignmentPage/AssignmentPage.tsx +++ b/frontend/frontend/src/pages/assignmentPage/AssignmentPage.tsx @@ -2,10 +2,17 @@ import { Header } from '../../components/Header.tsx' import FileUploadButton from '../../components/FileUploadButton.tsx' import { SubmissionListItemStudentPage } from '../../components/SubmissionListItemStudentPage.tsx' import { SubmissionListItemTeacherPage } from '../../components/SubmissionListItemTeacherPage.tsx' -import {Card, Button, Divider, EvenlySpacedRow, SecondaryButton} from '../../components/CustomComponents.tsx' +import { + Card, + Button, + Divider, + EvenlySpacedRow, + SecondaryButton, +} from '../../components/CustomComponents.tsx' import { Box, - CircularProgress, Grid, + CircularProgress, + Grid, List, Skeleton, Stack, @@ -141,41 +148,44 @@ export function AssignmentPage() { const downloadAllSubmissions = () => { const zip = new JSZip() const downloadPromises: Promise[] = [] - submissions.forEach(submission => { + submissions.forEach((submission) => { downloadPromises.push( new Promise(async (resolve, reject) => { try { // Get the submission details const submissionResponse = await instance.get( `/indieningen/${submission.indiening_id}/` - ); - const newSubmission = submissionResponse.data; + ) + const newSubmission = submissionResponse.data // Get the submission file const fileResponse = await instance.get( `/indieningen/${submission.indiening_id}/indiening_bestand/`, { responseType: 'blob' } - ); - let filename = 'indiening.zip'; + ) + let filename = 'indiening.zip' if (newSubmission.bestand) { - filename = newSubmission.bestand.replace(/^.*[\\/]/, ''); + filename = newSubmission.bestand.replace( + /^.*[\\/]/, + '' + ) } const blob = new Blob([fileResponse.data], { type: fileResponse.headers['content-type'], - }); + }) const file = new File([blob], filename, { type: fileResponse.headers['content-type'], - }); - newSubmission.bestand = file; - newSubmission.filename = filename; + }) + newSubmission.bestand = file + newSubmission.filename = filename // Add the file to the zip - zip.file(filename, fileResponse.data); - resolve(newSubmission); + zip.file(filename, fileResponse.data) + resolve(newSubmission) } catch (err) { - console.error(`Error downloading submission:`, err); - reject(err); + console.error(`Error downloading submission:`, err) + reject(err) } }) - ); + ) }) Promise.all(downloadPromises) .then(() => { @@ -184,7 +194,8 @@ export function AssignmentPage() { const url = window.URL.createObjectURL(blob) const a = document.createElement('a') a.href = url - a.download = 'all_submissions_' + assignment?.titel + '_.zip' + a.download = + 'all_submissions_' + assignment?.titel + '_.zip' document.body.appendChild(a) a.click() a.remove() @@ -365,7 +376,7 @@ export function AssignmentPage() { {/* Assignment description */} - + - - {t('group')} - , - - {t('time')} - , - - Score - , - - Status - , - - {t('download')} - - ]} - /> - - - + {t('group')} + , + + {t('time')} + , + + Score + , + + Status + , + + {t('download')} + , + ]} + /> + + + - - - {loading ? ( - [...Array(3)].map((_, index) => ( - - )) - ) : ( - <> - {groups.map((group,index) => ( + > + + + {loading ? ( + [...Array(3)].map( + (_, index) => ( + + ) + ) + ) : ( <> - {index != 0 ? : <>} - - group.groep_id - ) - ) + - 1 - ).toString()} - group_id={group.groep_id.toString()} - assignment_id={ - assignmentId - ? assignmentId - : '' - } - course_id={ - courseId - ? courseId - : '' - } - /> + {groups.map( + (group, index) => ( + <> + {index != + 0 ? ( + + ) : ( + <> + )} + + group.groep_id + ) + ) + + 1 + ).toString()} + group_id={group.groep_id.toString()} + assignment_id={ + assignmentId + ? assignmentId + : '' + } + course_id={ + courseId + ? courseId + : '' + } + /> + + ) + )} - ))} - - )} - + )} + @@ -707,22 +752,34 @@ export function AssignmentPage() { padding: 3, }} > - - {t('submission')} - , - - {t('time')} - , - - Status - - ]}/> + + {t('submission')} + , + + {t('time')} + , + + Status + , + ]} + /> - + @@ -756,13 +813,24 @@ export function AssignmentPage() { ? 1 : -1 ) - .map((submission,index) => ( + .map( + ( + submission, + index + ) => ( - {index != 0 ? : <>} + {index != + 0 ? ( + + ) : ( + <> + + + )} - - - - - - - + + + + - - {t('submit')} - - - - - + + + + {t('submit')} + + + + + void,handleLeave: ()=> void){ - if(isin){ +function joinLeaveButton( + isin: boolean, + handleJoin: () => void, + handleLeave: () => void +) { + if (isin) { return ( <>
{loading ? ( @@ -784,7 +805,9 @@ export function GroupsPage() { {chunkArray( filteredStudents, Math.ceil( - Math.sqrt(filteredStudents.length) + Math.sqrt( + filteredStudents.length + ) ) ).map( (students) => ( @@ -817,23 +840,23 @@ export function GroupsPage() { '' ? student : studentNames.get( - student - )} + student + )} = - newGroupSize + parseInt( + currentGroup + ) + ] + .studenten + .length >= + newGroupSize : true } onClick={() => { @@ -941,9 +964,9 @@ export function GroupsPage() { } function chunkArray(arr: T[], chunkSize: number): T[][] { - let result: T[][] = [] + const result: T[][] = [] for (let i = 0; i < arr.length; i += chunkSize) { - let chunk: T[] = arr.slice(i, i + chunkSize) + const chunk: T[] = arr.slice(i, i + chunkSize) result.push(chunk) } return result diff --git a/frontend/frontend/src/pages/scoresPage/ProjectScoresPage.tsx b/frontend/frontend/src/pages/scoresPage/ProjectScoresPage.tsx index 09ae0368..c82b8b9d 100644 --- a/frontend/frontend/src/pages/scoresPage/ProjectScoresPage.tsx +++ b/frontend/frontend/src/pages/scoresPage/ProjectScoresPage.tsx @@ -167,38 +167,41 @@ export function ProjectScoresPage() { groepen .filter((groep) => groep.lastSubmission !== undefined) .map((groep) => groep.lastSubmission) - .forEach(submission => { + .forEach((submission) => { downloadPromises.push( new Promise(async (resolve, reject) => { try { // Get the submission details const submissionResponse = await instance.get( `/indieningen/${submission?.indiening_id}/` - ); - const newSubmission = submissionResponse.data; + ) + const newSubmission = submissionResponse.data // Get the submission file const fileResponse = await instance.get( `/indieningen/${submission?.indiening_id}/indiening_bestand/`, { responseType: 'blob' } - ); - let filename = 'indiening.zip'; + ) + let filename = 'indiening.zip' if (newSubmission.bestand) { - filename = newSubmission.bestand.replace(/^.*[\\/]/, ''); + filename = newSubmission.bestand.replace( + /^.*[\\/]/, + '' + ) } const blob = new Blob([fileResponse.data], { type: fileResponse.headers['content-type'], - }); + }) const file = new File([blob], filename, { type: fileResponse.headers['content-type'], - }); - newSubmission.bestand = file; - newSubmission.filename = filename; + }) + newSubmission.bestand = file + newSubmission.filename = filename // Add the file to the zip - zip.file(filename, fileResponse.data); - resolve(newSubmission); + zip.file(filename, fileResponse.data) + resolve(newSubmission) } catch (err) { - console.error(`Error downloading submission:`, err); - reject(err); + console.error(`Error downloading submission:`, err) + reject(err) } }) ) @@ -210,7 +213,8 @@ export function ProjectScoresPage() { const url = window.URL.createObjectURL(blob) const a = document.createElement('a') a.href = url - a.download = 'all_submissions_' + project?.titel +'_.zip' + a.download = + 'all_submissions_' + project?.titel + '_.zip' document.body.appendChild(a) a.click() a.remove() @@ -299,149 +303,168 @@ export function ProjectScoresPage() { <> {user?.is_lesgever ? ( // Rendering UI for teacher - <> - -
- {/* Main content box */} - - - {/* Render StudentsView component if project is defined */} - {loading ? ( - - - - ) : ( <> - {project && ( - +
- )} - - )} - - {/* Footer section with action buttons */} - - - - + {/* Main content box */} - - - - - {loading ? ( - - ) : ( - <> - setOpenSaveScoresPopup(true)} + - - - - )} - setOpenDeleteScoresPopup(true)} - sx={{ - backgroundColor: 'secondary.main', - borderRadius: 2, - }} - > - - - - - {/* Popup for confirming saving scores */} - setOpenSaveScoresPopup(false)} - doAction={saveScores} - /> - {/* Popup for confirming deletion of scores */} - setOpenDeleteScoresPopup(false)} - doAction={deleteScores} - /> - + {/* Render StudentsView component if project is defined */} + {loading ? ( + + + + ) : ( + <> + {project && ( + + )} + + )} + + {/* Footer section with action buttons */} + + + + + + + + + + {loading ? ( + + ) : ( + <> + + setOpenSaveScoresPopup( + true + ) + } + sx={{ + color: 'background.default', + '&:hover': { + color: 'text.primary', + }, + backgroundColor: + 'primary.main', + borderRadius: 2, + }} + > + + + + )} + + setOpenDeleteScoresPopup(true) + } + sx={{ + backgroundColor: + 'secondary.main', + borderRadius: 2, + }} + > + + + + + {/* Popup for confirming saving scores */} + + setOpenSaveScoresPopup(false) + } + doAction={saveScores} + /> + {/* Popup for confirming deletion of scores */} + + setOpenDeleteScoresPopup(false) + } + doAction={deleteScores} + /> + + + ) : ( + navigate('*') + )} + + )} - ):( - navigate('*') - )} - -)} - -)} + ) +} diff --git a/frontend/frontend/src/pages/scoresPage/StudentScoreListItem.tsx b/frontend/frontend/src/pages/scoresPage/StudentScoreListItem.tsx index 7805f909..0a6ac60a 100644 --- a/frontend/frontend/src/pages/scoresPage/StudentScoreListItem.tsx +++ b/frontend/frontend/src/pages/scoresPage/StudentScoreListItem.tsx @@ -65,22 +65,22 @@ export function StudentScoreListItem({ // Get the submission details const submissionResponse = await instance.get( `/indieningen/${lastSubmission?.indiening_id}/` - ); - const newSubmission = submissionResponse.data; + ) + const newSubmission = submissionResponse.data // Get the submission file const fileResponse = await instance.get( `/indieningen/${lastSubmission?.indiening_id}/indiening_bestand/`, { responseType: 'blob' } - ); + ) if (newSubmission.bestand) { - filename = newSubmission.bestand.replace(/^.*[\\/]/, ''); + filename = newSubmission.bestand.replace(/^.*[\\/]/, '') } const blob = new Blob([fileResponse.data], { type: fileResponse.headers['content-type'], - }); + }) const file = new File([blob], filename, { type: fileResponse.headers['content-type'], - }); + }) const url = window.URL.createObjectURL(file) const a = document.createElement('a') a.href = url @@ -155,24 +155,24 @@ export function StudentScoreListItem({ )} {/* Display download icon */} - - -
- {lastSubmission ? ( - - ) : ( - - )} -
-
-
+ + +
+ {lastSubmission ? ( + + ) : ( + + )} +
+
+
diff --git a/frontend/frontend/src/pages/subjectsPage/AddChangeSubjectPage.tsx b/frontend/frontend/src/pages/subjectsPage/AddChangeSubjectPage.tsx index 7868a6fc..946cccde 100644 --- a/frontend/frontend/src/pages/subjectsPage/AddChangeSubjectPage.tsx +++ b/frontend/frontend/src/pages/subjectsPage/AddChangeSubjectPage.tsx @@ -9,7 +9,7 @@ import { Stack, TextField, Typography, - CircularProgress + CircularProgress, } from '@mui/material' import { Header } from '../../components/Header' import { Button } from '../../components/CustomComponents.tsx' @@ -572,157 +572,176 @@ export function AddChangeSubjectPage() { <> {user?.is_lesgever ? ( // Rendering UI for teacher - <> - -
- - - - - {t('subject_name') + ':'} - - {loading ? ( - + +
- ) : ( - - setTitle(event.target.value) - } - sx={{ height: 60 }} - /> - )} - - - - - - - - - {t('students')} - - - - {UserList( - loading, - students, - setSelectedStudent, - setOpenStudent - )} - - - - {UploadPart( - studentFile, - handleStudentFileChange, - setEmailStudent, - handleAddStudent, - t('upload_students') - )} - - - {DialogWindow( - handleCloseStudent, - openStudent, - handleRemoveStudent, - t('delete_student') - )} - - - - - {t('teachers')} - - - - {UserList( - loading, - teachers, - setSelectedTeacher, - setOpenTeacher - )} - - - - {UploadPart( - teacherFile, - handleTeacherFileChange, - setEmailTeacher, - handleAddTeacher, - t('upload_teachers') - )} - - - {DialogWindow( - handleCloseTeacher, - openTeacher, - handleRemoveTeacher, - t('delete_teacher') + + + + + {t('subject_name') + ':'} + + {loading ? ( + + ) : ( + + setTitle( + event.target.value + ) + } + sx={{ height: 60 }} + /> + )} + + + + + + + + + {t('students')} + + + + {UserList( + loading, + students, + setSelectedStudent, + setOpenStudent + )} + + + + {UploadPart( + studentFile, + handleStudentFileChange, + setEmailStudent, + handleAddStudent, + t('upload_students') + )} + + + {DialogWindow( + handleCloseStudent, + openStudent, + handleRemoveStudent, + t('delete_student') + )} + + + + + {t('teachers')} + + + + {UserList( + loading, + teachers, + setSelectedTeacher, + setOpenTeacher + )} + + + + {UploadPart( + teacherFile, + handleTeacherFileChange, + setEmailTeacher, + handleAddTeacher, + t('upload_teachers') + )} + + + {DialogWindow( + handleCloseTeacher, + openTeacher, + handleRemoveTeacher, + t('delete_teacher') + )} + + + + ) : ( + navigate('*') )} - - + + )} - ):( - navigate('*') - )} - -)} - -)} + ) +} diff --git a/frontend/frontend/src/pages/subjectsPage/AssignmentListItemSubjectsPage.tsx b/frontend/frontend/src/pages/subjectsPage/AssignmentListItemSubjectsPage.tsx index 59e3112d..516eda48 100644 --- a/frontend/frontend/src/pages/subjectsPage/AssignmentListItemSubjectsPage.tsx +++ b/frontend/frontend/src/pages/subjectsPage/AssignmentListItemSubjectsPage.tsx @@ -13,7 +13,7 @@ import DeleteOutlinedIcon from '@mui/icons-material/DeleteOutlined' import React, { useState } from 'react' import dayjs, { Dayjs } from 'dayjs' import { Score } from '../../components/SubmissionListItemTeacherPage.tsx' -import {EvenlySpacedRow} from "../../components/CustomComponents.tsx"; +import { EvenlySpacedRow } from '../../components/CustomComponents.tsx' /** * This component is used to display a single assignment in the list of assignments. @@ -72,77 +72,82 @@ export function AssignmentListItemSubjectsPage({ return ( <> - + sx={{ maxHeight: '30px' }} + onClick={handleProjectClick} + > {isStudent ? ( - , - , - 0 - ? submissions > 1 - ? submissions + - ' ' + - t('submissions') - : submissions + - ' ' + - t('submission') - : t('no_submissions') - } - />, - <> - {submissions > 0 ? ( + , - ) : ( + />, - )} - - ]}/> + primary={ + submissions > 0 + ? submissions > 1 + ? submissions + + ' ' + + t('submissions') + : submissions + + ' ' + + t('submission') + : t('no_submissions') + } + />, + <> + {submissions > 0 ? ( + + ) : ( + + )} + , + ]} + /> ) : ( <> {/* In case of the user being the teacher: */} - , - , - ]}/> + , + , + , + ]} + /> )} diff --git a/frontend/frontend/src/pages/subjectsPage/ProjectsView.tsx b/frontend/frontend/src/pages/subjectsPage/ProjectsView.tsx index 09f1e01c..0e7a64e4 100644 --- a/frontend/frontend/src/pages/subjectsPage/ProjectsView.tsx +++ b/frontend/frontend/src/pages/subjectsPage/ProjectsView.tsx @@ -1,4 +1,8 @@ -import {Card, Divider, EvenlySpacedRow} from '../../components/CustomComponents.tsx' +import { + Card, + Divider, + EvenlySpacedRow, +} from '../../components/CustomComponents.tsx' import { Box, Skeleton, Typography } from '@mui/material' import List from '@mui/material/List' import { t } from 'i18next' @@ -151,56 +155,81 @@ export function ProjectsView({ return ( <> - - {!gebruiker.is_lesgever ? ( - <> - {/* Show the UI from the perspective of a student. */} - - Project - , - - Deadline - , - - {t('submissions')} - , - - Score - - ]}/> - - ) : ( - <> - {/* Show the UI from the perspective of a teacher. */} - - Project - , - - Deadline - , - - {t('edit')} - ]} - /> - - )} - - + + {!gebruiker.is_lesgever ? ( + <> + {/* Show the UI from the perspective of a student. */} + + Project + , + + Deadline + , + + {t('submissions')} + , + + Score + , + ]} + /> + + ) : ( + <> + {/* Show the UI from the perspective of a teacher. */} + + Project + , + + Deadline + , + + {t('edit')} + , + ]} + /> + + )} + + {/* The list below will display the projects with their information */} @@ -233,7 +262,7 @@ export function ProjectsView({ ) .map((project) => ( <> - + {/* List of Students */} {students.length > 0 ? ( - - {students.map((student) => ( - - - - ))} - + + {students.map((student) => ( + + + + ))} + ) : ( - {t('loading') + ' ' + t('students') + '...'} + + {t('loading') + ' ' + t('students') + '...'} + )} diff --git a/frontend/frontend/src/pages/subjectsPage/SubjectsPage.tsx b/frontend/frontend/src/pages/subjectsPage/SubjectsPage.tsx index 3770ae4b..16b3a0d3 100644 --- a/frontend/frontend/src/pages/subjectsPage/SubjectsPage.tsx +++ b/frontend/frontend/src/pages/subjectsPage/SubjectsPage.tsx @@ -1,7 +1,6 @@ import { Header } from '../../components/Header' import { Box, - Card, CircularProgress, Grid, IconButton, @@ -71,7 +70,7 @@ export function SubjectsPage() { // State for loading the page const [loading, setLoading] = useState(true) const [userLoading, setUserLoading] = useState(true) - const [studentsLoading, setStudentsLoading] = useState(true); + const [studentsLoading, setStudentsLoading] = useState(true) useEffect(() => { // Get the data for this course. @@ -136,27 +135,27 @@ export function SubjectsPage() { useEffect(() => { async function fetchStudents() { - setStudentsLoading(true); - const temp_students = []; + setStudentsLoading(true) + const temp_students = [] for (const s of course?.studenten || []) { try { - const userResponse = await instance.get(`/gebruikers/${s}/`); - temp_students.push(userResponse.data); + const userResponse = await instance.get(`/gebruikers/${s}/`) + temp_students.push(userResponse.data) } catch (error) { - console.error('Error fetching student data:', error); - setFetchError(true); + console.error('Error fetching student data:', error) + setFetchError(true) } } // Update the state with the fetched data - setStudents(temp_students); - setStudentsLoading(false); + setStudents(temp_students) + setStudentsLoading(false) } - + // Fetch students fetchStudents().catch((error) => console.error('Error fetching students data:', error) - ); - }, [course]); + ) + }, [course]) const addProject = () => { console.log('add project') @@ -261,15 +260,13 @@ export function SubjectsPage() { }} > {/* Give the student the option to select current or archived projects. */} - {course.gearchiveerd? + {course.gearchiveerd ? ( - : + ) : ( , ]} /> - } + )} - {course.gearchiveerd? + {course.gearchiveerd ? ( - undefined - } - archiveAssignment={() => - undefined - } + deleteAssignment={() => undefined} + archiveAssignment={() => undefined} changeVisibilityAssignment={() => undefined } courseId={courseID} /> - : + ) : ( , ]} /> - } + )} - + diff --git a/frontend/frontend/src/pages/submissionPage/SubmissionPage.tsx b/frontend/frontend/src/pages/submissionPage/SubmissionPage.tsx index 3f5af53d..988d2b4e 100644 --- a/frontend/frontend/src/pages/submissionPage/SubmissionPage.tsx +++ b/frontend/frontend/src/pages/submissionPage/SubmissionPage.tsx @@ -129,17 +129,18 @@ export function SubmissionPage() { ) setRestrictions(restrictions.data) - const submissionResponse = await instance.get(`indieningen/${submissionId}/`) + const submissionResponse = await instance.get( + `indieningen/${submissionId}/` + ) //Get the submission file const newSubmission: Submission = submissionResponse.data - newSubmission.filename = submissionResponse.data.bestand.replace( - /^.*[\\/]/, - '' - ) + newSubmission.filename = + submissionResponse.data.bestand.replace(/^.*[\\/]/, '') newSubmission.bestand = await instance .get(`/indieningen/${submissionId}/indiening_bestand`, { responseType: 'blob', - }).then((res) => { + }) + .then((res) => { let filename = 'indiening.zip' if (newSubmission.filename) { filename = newSubmission.filename diff --git a/frontend/frontend/src/routes.tsx b/frontend/frontend/src/routes.tsx index d6bca41d..7762149f 100644 --- a/frontend/frontend/src/routes.tsx +++ b/frontend/frontend/src/routes.tsx @@ -8,7 +8,7 @@ import ErrorPage from './pages/ErrorPage.tsx' import MainPage from './pages/mainPage/MainPage.tsx' import { GroupsPage } from './pages/groupsPage/GroupsPage.tsx' import { AssignmentPage } from './pages/assignmentPage/AssignmentPage.tsx' -import {ChooseGroup} from "./pages/groupsPage/ChooseGroup.tsx"; +import { ChooseGroup } from './pages/groupsPage/ChooseGroup.tsx' //TODO: add change/add course page when implemented const router = createBrowserRouter([ From 3130bd3d5020e984b8fc4cfebd54a1fd01a831bd Mon Sep 17 00:00:00 2001 From: Ben De Meurichy Date: Sun, 19 May 2024 17:08:25 +0200 Subject: [PATCH 15/24] run npm format --- .../src/components/CustomComponents.tsx | 45 +- .../src/components/DeadlineCalendar.tsx | 62 +- .../SubmissionListItemStudentPage.tsx | 56 +- .../SubmissionListItemTeacherPage.tsx | 150 +-- .../AddChangeAssignmentPage.tsx | 1139 +++++++++-------- .../pages/assignmentPage/AssignmentPage.tsx | 339 +++-- .../src/pages/groupsPage/ChooseGroup.tsx | 784 ++++++++---- .../pages/scoresPage/ProjectScoresPage.tsx | 331 ++--- .../pages/scoresPage/StudentScoreListItem.tsx | 48 +- .../subjectsPage/AddChangeSubjectPage.tsx | 323 ++--- .../AssignmentListItemSubjectsPage.tsx | 124 +- .../src/pages/subjectsPage/ProjectsView.tsx | 133 +- .../src/pages/subjectsPage/StudentPopUp.tsx | 32 +- .../src/pages/subjectsPage/SubjectsPage.tsx | 56 +- .../pages/submissionPage/SubmissionPage.tsx | 13 +- frontend/frontend/src/routes.tsx | 2 +- 16 files changed, 2101 insertions(+), 1536 deletions(-) diff --git a/frontend/frontend/src/components/CustomComponents.tsx b/frontend/frontend/src/components/CustomComponents.tsx index 848b299a..f6edd286 100644 --- a/frontend/frontend/src/components/CustomComponents.tsx +++ b/frontend/frontend/src/components/CustomComponents.tsx @@ -1,9 +1,9 @@ -import { darken,lighten } from '@mui/system'; +import { darken, lighten } from '@mui/system' import { Button as BaseButton, Card as BaseCard, Divider as BaseDivider, - Box + Box, } from '@mui/material' import theme from '../Theme.ts' @@ -19,7 +19,7 @@ export const Button = ({ children, ...props }: any) => { textTransform: 'none', color: 'primary.contrastText', '&:hover': { - backgroundColor: darken(theme.palette.primary.main,0.5), + backgroundColor: darken(theme.palette.primary.main, 0.5), }, }} {...props} @@ -41,7 +41,7 @@ export const SecundaryButton = ({ children, ...props }: any) => { textTransform: 'none', color: 'secondary.contrastText', '&:hover': { - backgroundColor: darken(theme.palette.secondary.main,0.2), + backgroundColor: darken(theme.palette.secondary.main, 0.2), }, }} {...props} @@ -81,33 +81,30 @@ export const Divider = ({ children, ...props }: any) => { ) } -export const EvenlySpacedRow = ({items}) => { +export const EvenlySpacedRow = ({ items }) => { return ( - + {items.map((item, index) => ( - - - {item} - + width={ + index == 0 || index == items.length - 1 + ? 50 / items.length + '%' + : (100 - 100 / items.length) / (items.length - 2) + + '%' + } + sx={{ + //border: '1px solid red', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + }} + > + {item} ))} - + ) } - - export default { Button, Card, Divider, EvenlySpacedRow } diff --git a/frontend/frontend/src/components/DeadlineCalendar.tsx b/frontend/frontend/src/components/DeadlineCalendar.tsx index 8772029d..bc87c398 100644 --- a/frontend/frontend/src/components/DeadlineCalendar.tsx +++ b/frontend/frontend/src/components/DeadlineCalendar.tsx @@ -5,7 +5,17 @@ import { PickersDayProps, } from '@mui/x-date-pickers' import dayjs, { Dayjs } from 'dayjs' -import { Badge, SxProps, Stack, Typography, Box, List, ListItem, ListItemButton, ListItemText } from '@mui/material' +import { + Badge, + SxProps, + Stack, + Typography, + Box, + List, + ListItem, + ListItemButton, + ListItemText, +} from '@mui/material' import { useEffect, useRef, useState } from 'react' import AssignmentIcon from '@mui/icons-material/Assignment' import { useNavigate } from 'react-router-dom' @@ -95,22 +105,26 @@ function DeadlineMenu({ assignments, selectedDay }: DeadlineMenuProps) { {assignments - .filter((assignment: project) => - dayjs(assignment.deadline).isSame(selectedDay, 'day') - ).map((assignment: project) => - - handleProjectClick(assignment.vak, assignment.project_id)} - > - - - - )} + .filter((assignment: project) => + dayjs(assignment.deadline).isSame(selectedDay, 'day') + ) + .map((assignment: project) => ( + + + handleProjectClick( + assignment.vak, + assignment.project_id + ) + } + > + + + + ))} ) @@ -121,7 +135,10 @@ interface DeadlineCalendarProps { assignments: project[] } -export function DeadlineCalendar({ deadlines, assignments }: DeadlineCalendarProps) { +export function DeadlineCalendar({ + deadlines, + assignments, +}: DeadlineCalendarProps) { const requestAbortController = useRef(null) const [isLoading, setIsLoading] = useState(false) const [highlightedDays, setHighlightedDays] = useState([]) @@ -173,9 +190,7 @@ export function DeadlineCalendar({ deadlines, assignments }: DeadlineCalendarPro return ( <> - + {/*Calendar*/} - + ) diff --git a/frontend/frontend/src/components/SubmissionListItemStudentPage.tsx b/frontend/frontend/src/components/SubmissionListItemStudentPage.tsx index 68840f6f..aafada4e 100644 --- a/frontend/frontend/src/components/SubmissionListItemStudentPage.tsx +++ b/frontend/frontend/src/components/SubmissionListItemStudentPage.tsx @@ -1,4 +1,4 @@ -import { EvenlySpacedRow} from "./CustomComponents.tsx"; +import { EvenlySpacedRow } from './CustomComponents.tsx' import { ListItem, ListItemButton, @@ -53,31 +53,35 @@ export function SubmissionListItemStudentPage({ <> - , - , - - - {status ? ( - - ) : ( - - )} - - - ]}/> + , + , + + + {status ? ( + + ) : ( + + )} + + , + ]} + /> diff --git a/frontend/frontend/src/components/SubmissionListItemTeacherPage.tsx b/frontend/frontend/src/components/SubmissionListItemTeacherPage.tsx index cfaa2dc4..f1d82bcc 100644 --- a/frontend/frontend/src/components/SubmissionListItemTeacherPage.tsx +++ b/frontend/frontend/src/components/SubmissionListItemTeacherPage.tsx @@ -3,7 +3,7 @@ import { ListItemButton, ListItemIcon, ListItemText, - Box + Box, } from '@mui/material' import { useNavigate } from 'react-router-dom' import DownloadIcon from '@mui/icons-material/Download' @@ -14,7 +14,7 @@ import instance from '../axiosConfig' import { Submission } from '../pages/submissionPage/SubmissionPage.tsx' import { t } from 'i18next' import dayjs from 'dayjs' -import {EvenlySpacedRow} from "./CustomComponents.tsx"; +import { EvenlySpacedRow } from './CustomComponents.tsx' interface SubmissionListItemTeacherPageProps { relative_group_id: string @@ -63,17 +63,21 @@ export function SubmissionListItemTeacherPage({ submissionsResponse.data[ submissionsResponse.data.length - 1 ] - const lastSubmissionResponse = await instance.get(`indieningen/${lastSubmission.indiening_id}/`) + const lastSubmissionResponse = await instance.get( + `indieningen/${lastSubmission.indiening_id}/` + ) //Get the submission file const newSubmission: Submission = lastSubmissionResponse.data - newSubmission.filename = lastSubmissionResponse.data.bestand.replace( - /^.*[\\/]/, - '' - ) + newSubmission.filename = + lastSubmissionResponse.data.bestand.replace(/^.*[\\/]/, '') newSubmission.bestand = await instance - .get(`/indieningen/${lastSubmission.indiening_id}/indiening_bestand`, { - responseType: 'blob', - }).then((res) => { + .get( + `/indieningen/${lastSubmission.indiening_id}/indiening_bestand`, + { + responseType: 'blob', + } + ) + .then((res) => { let filename = 'indiening.zip' if (newSubmission.filename) { filename = newSubmission.filename @@ -107,9 +111,7 @@ export function SubmissionListItemTeacherPage({ const url = window.URL.createObjectURL(submitted?.bestand) const a = document.createElement('a') a.href = url - a.download = submitted.filename - ? submitted.filename - : 'opgave.zip' + a.download = submitted.filename ? submitted.filename : 'opgave.zip' document.body.appendChild(a) a.click() a.remove() @@ -128,70 +130,72 @@ export function SubmissionListItemTeacherPage({ return ( <> - - + + , - , - , - - - {!submitted?.status ? ( - - ) : ( - submitted !== undefined && ( - - ) - )} - - , - - -
- {submitted ? ( - , + , + , + + + {!submitted?.status ? ( + ) : ( - + submitted !== undefined && ( + + ) )} -
-
-
- ]}> -
+ +
, + + +
+ {submitted ? ( + + ) : ( + + )} +
+
+
, + ]} + >
diff --git a/frontend/frontend/src/pages/addChangeAssignmentPage/AddChangeAssignmentPage.tsx b/frontend/frontend/src/pages/addChangeAssignmentPage/AddChangeAssignmentPage.tsx index 33d50574..5ed43e36 100644 --- a/frontend/frontend/src/pages/addChangeAssignmentPage/AddChangeAssignmentPage.tsx +++ b/frontend/frontend/src/pages/addChangeAssignmentPage/AddChangeAssignmentPage.tsx @@ -191,15 +191,11 @@ export function AddChangeAssignmentPage() { setVisible(assignment.zichtbaar) if (assignment.deadline !== null) { - setDueDate( - dayjs(assignment.deadline) - ) + setDueDate(dayjs(assignment.deadline)) console.log('deadline' + assignment.deadline) } if (assignment.extra_deadline !== null) { - setExtraDueDate( - dayjs(assignment.extra_deadline) - ) + setExtraDueDate(dayjs(assignment.extra_deadline)) console.log( 'extra deadline' + assignment.extra_deadline ) @@ -472,529 +468,622 @@ export function AddChangeAssignmentPage() { <> {user?.is_lesgever ? ( // Rendering UI for teacher - <> - {/* Stack container for layout */} - - {/*very ugly but it works functionally*/} - {loading ? ( -
- ) : ( -
- )} - {/* Form for submitting assignment */} - - - - {/* Here the user gets to specify the assignment name */} - - {t('assignmentName')} - - {loading ? ( - - ) : ( - - setTitle(event.target.value) - } - /> - )} - - {/* File Upload button */} - - {loading ? ( - { - console.log('loading') - }} - fileTypes={['.pdf', '.zip']} - path={new File([], 'loading...')} - /> - ) : ( - - )} - - - {/* Deadline section. + <> + {/* Stack container for layout */} + + {/*very ugly but it works functionally*/} + {loading ? ( +
+ ) : ( +
+ )} + {/* Form for submitting assignment */} + + + + {/* Here the user gets to specify the assignment name */} + + {t('assignmentName')} + + {loading ? ( + + ) : ( + + setTitle( + event.target.value + ) + } + /> + )} + + {/* File Upload button */} + + {loading ? ( + { + console.log('loading') + }} + fileTypes={['.pdf', '.zip']} + path={ + new File( + [], + 'loading...' + ) + } + /> + ) : ( + + )} + + + {/* Deadline section. There is both the normal deadline, and an extra deadline in case people need more time. */} - - - {/* This section renders the normal deadline. */} - - Deadline: - - {loading ? ( - - ) : ( - - - SetDeadlineError(newError) - } - slotProps={{ - field: { - clearable: true, - onClear: () => setCleared(true), - }, - textField: { - helperText: errorMessage, - }, - }} - onChange={(newValue) => - setDueDate(newValue) - } - /> - - )} - - - {/* This section renders the extra deadline. */} - - Extra Deadline: - - {loading ? ( - - ) : ( - - setCleared(true), - }, - textField: { - error: deadlineCheckError, - helperText: deadlineCheckError - ? t('deadlineCheck') - : '', - }, + - setExtraDueDate(newValue) - } - /> - - )} - - - {/* Description section */} - - - - {t('description')} - - {loading ? ( - - ) : ( - - setDescription(event.target.value) - } - fullWidth - error={assignmentErrors.description} - // Show an error message if the description is not filled in. - helperText={ - assignmentErrors.description - ? t('descriptionName') + - ' ' + - t('is_required') - : '' - } - sx={{ - overflowY: 'auto', - maxHeight: '25svh', - }} - /> - )} - - - {/* Restrictions section */} - - - - {t('restrictions')} - - - {/*This list will render the restrictions that are added to the assignment.*/} - - {loading ? ( - - ) : ( - <> - {restrictions.map( - (restriction, index) => { - return ( - - - - ) - } - )} - - )} - - - - - - setRestrictions(newRestrictions) - } - > - - - - - {/* Main actions section */} - - - - {visible ? ( - setVisible(!visible)} + gap={5} > - - - ) : ( - setVisible(!visible)} + + {/* This section renders the normal deadline. */} + + Deadline: + + {loading ? ( + + ) : ( + + + SetDeadlineError( + newError + ) + } + slotProps={{ + field: { + clearable: true, + onClear: () => + setCleared( + true + ), + }, + textField: { + helperText: + errorMessage, + }, + }} + onChange={(newValue) => + setDueDate(newValue) + } + /> + + )} + + + {/* This section renders the extra deadline. */} + + Extra Deadline: + + {loading ? ( + + ) : ( + + + setCleared( + true + ), + }, + textField: { + error: deadlineCheckError, + helperText: + deadlineCheckError + ? t( + 'deadlineCheck' + ) + : '', + }, + }} + onChange={(newValue) => + setExtraDueDate( + newValue + ) + } + /> + + )} + + + {/* Description section */} + + + + {t('description')} + + {loading ? ( + + ) : ( + + setDescription( + event.target.value + ) + } + fullWidth + error={ + assignmentErrors.description + } + // Show an error message if the description is not filled in. + helperText={ + assignmentErrors.description + ? t( + 'descriptionName' + ) + + ' ' + + t('is_required') + : '' + } + sx={{ + overflowY: 'auto', + maxHeight: '25svh', + }} + /> + )} + + + {/* Restrictions section */} + - - - )} - - + + {t('restrictions')} + + + {/*This list will render the restrictions that are added to the assignment.*/} + + {loading ? ( + + ) : ( + <> + {restrictions.map( + ( + restriction, + index + ) => { + return ( + + + + ) + } + )} + + )} + + + + + + setRestrictions( + newRestrictions + ) + } + > + + + + + {/* Main actions section */} + - - - - - {/* This section allows the teacher to set the maximum score for the assignment.*/} - - - Max Score - - {loading ? ( - - ) : ( - { - if (event.target.value !== '') { - const newScore = Math.max( - parseInt( - event.target.value - ), - 0 - ) - SetMaxScore - ? SetMaxScore(newScore) - : undefined - } else { - SetMaxScore - ? SetMaxScore( - parseInt( - event.target.value - ) - ) - : undefined - } - }} - /> - )} - - - {/* Submit and Cancel buttons */} - - - setCancelConfirmation(true)} - sx={{ - backgroundColor: 'secondary.main', - borderRadius: 2, - }} - > - - - - - - - - - - - - - {/* Popup for adding restrictions */} - - {/* Confirmation popup for deleting project */} - - - {/* Confirmation popup for saving project */} - - {/* Confirmation popup for canceling changes*/} - - + + + {visible ? ( + + setVisible(!visible) + } + > + + + ) : ( + + setVisible(!visible) + } + > + + + )} + + + + + + + {/* This section allows the teacher to set the maximum score for the assignment.*/} + + + Max Score + + {loading ? ( + + ) : ( + { + if ( + event.target + .value !== + '' + ) { + const newScore = + Math.max( + parseInt( + event + .target + .value + ), + 0 + ) + SetMaxScore + ? SetMaxScore( + newScore + ) + : undefined + } else { + SetMaxScore + ? SetMaxScore( + parseInt( + event + .target + .value + ) + ) + : undefined + } + }} + /> + )} + + + {/* Submit and Cancel buttons */} + + + + setCancelConfirmation( + true + ) + } + sx={{ + backgroundColor: + 'secondary.main', + borderRadius: 2, + }} + > + + + + + + + + + + + + + {/* Popup for adding restrictions */} + + {/* Confirmation popup for deleting project */} + + + {/* Confirmation popup for saving project */} + + {/* Confirmation popup for canceling changes*/} + + + + ) : ( + navigate('*') + )} + + )} - ):( - navigate('*') - )} - -)} - -)} + ) +} diff --git a/frontend/frontend/src/pages/assignmentPage/AssignmentPage.tsx b/frontend/frontend/src/pages/assignmentPage/AssignmentPage.tsx index 9e8000f8..48950032 100644 --- a/frontend/frontend/src/pages/assignmentPage/AssignmentPage.tsx +++ b/frontend/frontend/src/pages/assignmentPage/AssignmentPage.tsx @@ -2,10 +2,17 @@ import { Header } from '../../components/Header.tsx' import FileUploadButton from '../../components/FileUploadButton.tsx' import { SubmissionListItemStudentPage } from '../../components/SubmissionListItemStudentPage.tsx' import { SubmissionListItemTeacherPage } from '../../components/SubmissionListItemTeacherPage.tsx' -import {Card, Button, Divider, EvenlySpacedRow, SecundaryButton} from '../../components/CustomComponents.tsx' +import { + Button, + Card, + Divider, + EvenlySpacedRow, + SecundaryButton, +} from '../../components/CustomComponents.tsx' import { Box, - CircularProgress, Grid, + CircularProgress, + Grid, List, Skeleton, Stack, @@ -141,41 +148,44 @@ export function AssignmentPage() { const downloadAllSubmissions = () => { const zip = new JSZip() const downloadPromises: Promise[] = [] - submissions.forEach(submission => { + submissions.forEach((submission) => { downloadPromises.push( new Promise(async (resolve, reject) => { try { // Get the submission details const submissionResponse = await instance.get( `/indieningen/${submission.indiening_id}/` - ); - const newSubmission = submissionResponse.data; + ) + const newSubmission = submissionResponse.data // Get the submission file const fileResponse = await instance.get( `/indieningen/${submission.indiening_id}/indiening_bestand/`, { responseType: 'blob' } - ); - let filename = 'indiening.zip'; + ) + let filename = 'indiening.zip' if (newSubmission.bestand) { - filename = newSubmission.bestand.replace(/^.*[\\/]/, ''); + filename = newSubmission.bestand.replace( + /^.*[\\/]/, + '' + ) } const blob = new Blob([fileResponse.data], { type: fileResponse.headers['content-type'], - }); + }) const file = new File([blob], filename, { type: fileResponse.headers['content-type'], - }); - newSubmission.bestand = file; - newSubmission.filename = filename; + }) + newSubmission.bestand = file + newSubmission.filename = filename // Add the file to the zip - zip.file(filename, fileResponse.data); - resolve(newSubmission); + zip.file(filename, fileResponse.data) + resolve(newSubmission) } catch (err) { - console.error(`Error downloading submission:`, err); - reject(err); + console.error(`Error downloading submission:`, err) + reject(err) } }) - ); + ) }) Promise.all(downloadPromises) .then(() => { @@ -184,7 +194,8 @@ export function AssignmentPage() { const url = window.URL.createObjectURL(blob) const a = document.createElement('a') a.href = url - a.download = 'all_submissions_' + assignment?.titel + '_.zip' + a.download = + 'all_submissions_' + assignment?.titel + '_.zip' document.body.appendChild(a) a.click() a.remove() @@ -365,7 +376,7 @@ export function AssignmentPage() { {/* Assignment description */} - + - - {t('group')} - , - - {t('time')} - , - - Score - , - - Status - , - - {t('download')} - - ]} - /> - - - + {t('group')} + , + + {t('time')} + , + + Score + , + + Status + , + + {t('download')} + , + ]} + /> + + + - - - {loading ? ( - [...Array(3)].map((_, index) => ( - - )) - ) : ( - <> - {groups.map((group,index) => ( + > + + + {loading ? ( + [...Array(3)].map( + (_, index) => ( + + ) + ) + ) : ( <> - {index != 0 ? : <>} - - group.groep_id - ) - ) + - 1 - ).toString()} - group_id={group.groep_id.toString()} - assignment_id={ - assignmentId - ? assignmentId - : '' - } - course_id={ - courseId - ? courseId - : '' - } - /> + {groups.map( + (group, index) => ( + <> + {index != + 0 ? ( + + ) : ( + <> + )} + + group.groep_id + ) + ) + + 1 + ).toString()} + group_id={group.groep_id.toString()} + assignment_id={ + assignmentId + ? assignmentId + : '' + } + course_id={ + courseId + ? courseId + : '' + } + /> + + ) + )} - ))} - - )} - + )} + @@ -717,22 +762,34 @@ export function AssignmentPage() { padding: 3, }} > - - {t('submission')} - , - - {t('time')} - , - - Status - - ]}/> + + {t('submission')} + , + + {t('time')} + , + + Status + , + ]} + /> - + @@ -766,13 +823,24 @@ export function AssignmentPage() { ? 1 : -1 ) - .map((submission,index) => ( + .map( + ( + submission, + index + ) => ( - {index != 0 ? : <>} + {index != + 0 ? ( + + ) : ( + <> + + + )} - - - - - - - + + + + - - {t('submit')} - - - - - + + + + {t('submit')} + + + + + void,handleLeave: ()=> void){ - if(isin){ +function joinLeaveButton( + isin: boolean, + handleJoin: () => void, + handleLeave: () => void +) { + if (isin) { return ( <> + {/* Main content box */} - - - - - {loading ? ( - - ) : ( - <> - setOpenSaveScoresPopup(true)} + - - - - )} - setOpenDeleteScoresPopup(true)} - sx={{ - backgroundColor: 'secondary.main', - borderRadius: 2, - }} - > - - - - - {/* Popup for confirming saving scores */} - setOpenSaveScoresPopup(false)} - doAction={saveScores} - /> - {/* Popup for confirming deletion of scores */} - setOpenDeleteScoresPopup(false)} - doAction={deleteScores} - /> - + {/* Render StudentsView component if project is defined */} + {loading ? ( + + + + ) : ( + <> + {project && ( + + )} + + )} + + {/* Footer section with action buttons */} + + + + + + + + + + {loading ? ( + + ) : ( + <> + + setOpenSaveScoresPopup( + true + ) + } + sx={{ + color: 'background.default', + '&:hover': { + color: 'text.primary', + }, + backgroundColor: + 'primary.main', + borderRadius: 2, + }} + > + + + + )} + + setOpenDeleteScoresPopup(true) + } + sx={{ + backgroundColor: + 'secondary.main', + borderRadius: 2, + }} + > + + + + + {/* Popup for confirming saving scores */} + + setOpenSaveScoresPopup(false) + } + doAction={saveScores} + /> + {/* Popup for confirming deletion of scores */} + + setOpenDeleteScoresPopup(false) + } + doAction={deleteScores} + /> + + + ) : ( + navigate('*') + )} + + )} - ):( - navigate('*') - )} - -)} - -)} + ) +} diff --git a/frontend/frontend/src/pages/scoresPage/StudentScoreListItem.tsx b/frontend/frontend/src/pages/scoresPage/StudentScoreListItem.tsx index 7805f909..0a6ac60a 100644 --- a/frontend/frontend/src/pages/scoresPage/StudentScoreListItem.tsx +++ b/frontend/frontend/src/pages/scoresPage/StudentScoreListItem.tsx @@ -65,22 +65,22 @@ export function StudentScoreListItem({ // Get the submission details const submissionResponse = await instance.get( `/indieningen/${lastSubmission?.indiening_id}/` - ); - const newSubmission = submissionResponse.data; + ) + const newSubmission = submissionResponse.data // Get the submission file const fileResponse = await instance.get( `/indieningen/${lastSubmission?.indiening_id}/indiening_bestand/`, { responseType: 'blob' } - ); + ) if (newSubmission.bestand) { - filename = newSubmission.bestand.replace(/^.*[\\/]/, ''); + filename = newSubmission.bestand.replace(/^.*[\\/]/, '') } const blob = new Blob([fileResponse.data], { type: fileResponse.headers['content-type'], - }); + }) const file = new File([blob], filename, { type: fileResponse.headers['content-type'], - }); + }) const url = window.URL.createObjectURL(file) const a = document.createElement('a') a.href = url @@ -155,24 +155,24 @@ export function StudentScoreListItem({ )} {/* Display download icon */} - - -
- {lastSubmission ? ( - - ) : ( - - )} -
-
-
+ + +
+ {lastSubmission ? ( + + ) : ( + + )} +
+
+
diff --git a/frontend/frontend/src/pages/subjectsPage/AddChangeSubjectPage.tsx b/frontend/frontend/src/pages/subjectsPage/AddChangeSubjectPage.tsx index 7868a6fc..946cccde 100644 --- a/frontend/frontend/src/pages/subjectsPage/AddChangeSubjectPage.tsx +++ b/frontend/frontend/src/pages/subjectsPage/AddChangeSubjectPage.tsx @@ -9,7 +9,7 @@ import { Stack, TextField, Typography, - CircularProgress + CircularProgress, } from '@mui/material' import { Header } from '../../components/Header' import { Button } from '../../components/CustomComponents.tsx' @@ -572,157 +572,176 @@ export function AddChangeSubjectPage() { <> {user?.is_lesgever ? ( // Rendering UI for teacher - <> - -
- - - - - {t('subject_name') + ':'} - - {loading ? ( - + +
- ) : ( - - setTitle(event.target.value) - } - sx={{ height: 60 }} - /> - )} - - - - - - - - - {t('students')} - - - - {UserList( - loading, - students, - setSelectedStudent, - setOpenStudent - )} - - - - {UploadPart( - studentFile, - handleStudentFileChange, - setEmailStudent, - handleAddStudent, - t('upload_students') - )} - - - {DialogWindow( - handleCloseStudent, - openStudent, - handleRemoveStudent, - t('delete_student') - )} - - - - - {t('teachers')} - - - - {UserList( - loading, - teachers, - setSelectedTeacher, - setOpenTeacher - )} - - - - {UploadPart( - teacherFile, - handleTeacherFileChange, - setEmailTeacher, - handleAddTeacher, - t('upload_teachers') - )} - - - {DialogWindow( - handleCloseTeacher, - openTeacher, - handleRemoveTeacher, - t('delete_teacher') + + + + + {t('subject_name') + ':'} + + {loading ? ( + + ) : ( + + setTitle( + event.target.value + ) + } + sx={{ height: 60 }} + /> + )} + + + + + + + + + {t('students')} + + + + {UserList( + loading, + students, + setSelectedStudent, + setOpenStudent + )} + + + + {UploadPart( + studentFile, + handleStudentFileChange, + setEmailStudent, + handleAddStudent, + t('upload_students') + )} + + + {DialogWindow( + handleCloseStudent, + openStudent, + handleRemoveStudent, + t('delete_student') + )} + + + + + {t('teachers')} + + + + {UserList( + loading, + teachers, + setSelectedTeacher, + setOpenTeacher + )} + + + + {UploadPart( + teacherFile, + handleTeacherFileChange, + setEmailTeacher, + handleAddTeacher, + t('upload_teachers') + )} + + + {DialogWindow( + handleCloseTeacher, + openTeacher, + handleRemoveTeacher, + t('delete_teacher') + )} + + + + ) : ( + navigate('*') )} - - + + )} - ):( - navigate('*') - )} - -)} - -)} + ) +} diff --git a/frontend/frontend/src/pages/subjectsPage/AssignmentListItemSubjectsPage.tsx b/frontend/frontend/src/pages/subjectsPage/AssignmentListItemSubjectsPage.tsx index 7c3f81ec..4872d9a6 100644 --- a/frontend/frontend/src/pages/subjectsPage/AssignmentListItemSubjectsPage.tsx +++ b/frontend/frontend/src/pages/subjectsPage/AssignmentListItemSubjectsPage.tsx @@ -13,7 +13,7 @@ import DeleteOutlinedIcon from '@mui/icons-material/DeleteOutlined' import React, { useState } from 'react' import dayjs, { Dayjs } from 'dayjs' import { Score } from '../../components/SubmissionListItemTeacherPage.tsx' -import {EvenlySpacedRow} from "../../components/CustomComponents.tsx"; +import { EvenlySpacedRow } from '../../components/CustomComponents.tsx' /** * This component is used to display a single assignment in the list of assignments. @@ -72,75 +72,79 @@ export function AssignmentListItemSubjectsPage({ return ( <> - {isStudent ? ( - , - , - 0 - ? submissions > 1 - ? submissions + - ' ' + - t('submissions') - : submissions + - ' ' + - t('submission') - : t('no_submissions') - } - />, - <> - {submissions > 0 ? ( + , - ) : ( + />, - )} - - ]}/> + primary={ + submissions > 0 + ? submissions > 1 + ? submissions + + ' ' + + t('submissions') + : submissions + + ' ' + + t('submission') + : t('no_submissions') + } + />, + <> + {submissions > 0 ? ( + + ) : ( + + )} + , + ]} + /> ) : ( <> {/* In case of the user being the teacher: */} - , - , - ]}/> + , + , + , + ]} + /> )} diff --git a/frontend/frontend/src/pages/subjectsPage/ProjectsView.tsx b/frontend/frontend/src/pages/subjectsPage/ProjectsView.tsx index 09f1e01c..0e7a64e4 100644 --- a/frontend/frontend/src/pages/subjectsPage/ProjectsView.tsx +++ b/frontend/frontend/src/pages/subjectsPage/ProjectsView.tsx @@ -1,4 +1,8 @@ -import {Card, Divider, EvenlySpacedRow} from '../../components/CustomComponents.tsx' +import { + Card, + Divider, + EvenlySpacedRow, +} from '../../components/CustomComponents.tsx' import { Box, Skeleton, Typography } from '@mui/material' import List from '@mui/material/List' import { t } from 'i18next' @@ -151,56 +155,81 @@ export function ProjectsView({ return ( <> - - {!gebruiker.is_lesgever ? ( - <> - {/* Show the UI from the perspective of a student. */} - - Project - , - - Deadline - , - - {t('submissions')} - , - - Score - - ]}/> - - ) : ( - <> - {/* Show the UI from the perspective of a teacher. */} - - Project - , - - Deadline - , - - {t('edit')} - ]} - /> - - )} - - + + {!gebruiker.is_lesgever ? ( + <> + {/* Show the UI from the perspective of a student. */} + + Project + , + + Deadline + , + + {t('submissions')} + , + + Score + , + ]} + /> + + ) : ( + <> + {/* Show the UI from the perspective of a teacher. */} + + Project + , + + Deadline + , + + {t('edit')} + , + ]} + /> + + )} + + {/* The list below will display the projects with their information */} @@ -233,7 +262,7 @@ export function ProjectsView({ ) .map((project) => ( <> - + {/* List of Students */} {students.length > 0 ? ( - - {students.map((student) => ( - - - - ))} - + + {students.map((student) => ( + + + + ))} + ) : ( - {t('loading') + ' ' + t('students') + '...'} + + {t('loading') + ' ' + t('students') + '...'} + )} diff --git a/frontend/frontend/src/pages/subjectsPage/SubjectsPage.tsx b/frontend/frontend/src/pages/subjectsPage/SubjectsPage.tsx index 3770ae4b..1be3d95a 100644 --- a/frontend/frontend/src/pages/subjectsPage/SubjectsPage.tsx +++ b/frontend/frontend/src/pages/subjectsPage/SubjectsPage.tsx @@ -71,7 +71,7 @@ export function SubjectsPage() { // State for loading the page const [loading, setLoading] = useState(true) const [userLoading, setUserLoading] = useState(true) - const [studentsLoading, setStudentsLoading] = useState(true); + const [studentsLoading, setStudentsLoading] = useState(true) useEffect(() => { // Get the data for this course. @@ -136,27 +136,27 @@ export function SubjectsPage() { useEffect(() => { async function fetchStudents() { - setStudentsLoading(true); - const temp_students = []; + setStudentsLoading(true) + const temp_students = [] for (const s of course?.studenten || []) { try { - const userResponse = await instance.get(`/gebruikers/${s}/`); - temp_students.push(userResponse.data); + const userResponse = await instance.get(`/gebruikers/${s}/`) + temp_students.push(userResponse.data) } catch (error) { - console.error('Error fetching student data:', error); - setFetchError(true); + console.error('Error fetching student data:', error) + setFetchError(true) } } // Update the state with the fetched data - setStudents(temp_students); - setStudentsLoading(false); + setStudents(temp_students) + setStudentsLoading(false) } - + // Fetch students fetchStudents().catch((error) => console.error('Error fetching students data:', error) - ); - }, [course]); + ) + }, [course]) const addProject = () => { console.log('add project') @@ -261,15 +261,13 @@ export function SubjectsPage() { }} > {/* Give the student the option to select current or archived projects. */} - {course.gearchiveerd? + {course.gearchiveerd ? ( - : + ) : ( , ]} /> - } + )} - {course.gearchiveerd? + {course.gearchiveerd ? ( - undefined - } - archiveAssignment={() => - undefined - } + deleteAssignment={() => undefined} + archiveAssignment={() => undefined} changeVisibilityAssignment={() => undefined } courseId={courseID} /> - : + ) : ( , ]} /> - } + )} - + diff --git a/frontend/frontend/src/pages/submissionPage/SubmissionPage.tsx b/frontend/frontend/src/pages/submissionPage/SubmissionPage.tsx index 3f5af53d..988d2b4e 100644 --- a/frontend/frontend/src/pages/submissionPage/SubmissionPage.tsx +++ b/frontend/frontend/src/pages/submissionPage/SubmissionPage.tsx @@ -129,17 +129,18 @@ export function SubmissionPage() { ) setRestrictions(restrictions.data) - const submissionResponse = await instance.get(`indieningen/${submissionId}/`) + const submissionResponse = await instance.get( + `indieningen/${submissionId}/` + ) //Get the submission file const newSubmission: Submission = submissionResponse.data - newSubmission.filename = submissionResponse.data.bestand.replace( - /^.*[\\/]/, - '' - ) + newSubmission.filename = + submissionResponse.data.bestand.replace(/^.*[\\/]/, '') newSubmission.bestand = await instance .get(`/indieningen/${submissionId}/indiening_bestand`, { responseType: 'blob', - }).then((res) => { + }) + .then((res) => { let filename = 'indiening.zip' if (newSubmission.filename) { filename = newSubmission.filename diff --git a/frontend/frontend/src/routes.tsx b/frontend/frontend/src/routes.tsx index d6bca41d..7762149f 100644 --- a/frontend/frontend/src/routes.tsx +++ b/frontend/frontend/src/routes.tsx @@ -8,7 +8,7 @@ import ErrorPage from './pages/ErrorPage.tsx' import MainPage from './pages/mainPage/MainPage.tsx' import { GroupsPage } from './pages/groupsPage/GroupsPage.tsx' import { AssignmentPage } from './pages/assignmentPage/AssignmentPage.tsx' -import {ChooseGroup} from "./pages/groupsPage/ChooseGroup.tsx"; +import { ChooseGroup } from './pages/groupsPage/ChooseGroup.tsx' //TODO: add change/add course page when implemented const router = createBrowserRouter([ From 9dedf3b21c234fd51286b7b5ececab2791f68602 Mon Sep 17 00:00:00 2001 From: Ben De Meurichy Date: Sun, 19 May 2024 17:11:36 +0200 Subject: [PATCH 16/24] Revert "inladen studenten bij groepen is niet meer onacceptabel traag" This reverts commit 3f6ea634864ddea3245f5263bc65d08419bc5bdc. --- .../src/pages/groupsPage/GroupsPage.tsx | 53 ++++++++++++------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/frontend/frontend/src/pages/groupsPage/GroupsPage.tsx b/frontend/frontend/src/pages/groupsPage/GroupsPage.tsx index 003057c6..38707a4d 100644 --- a/frontend/frontend/src/pages/groupsPage/GroupsPage.tsx +++ b/frontend/frontend/src/pages/groupsPage/GroupsPage.tsx @@ -30,8 +30,6 @@ import { Add } from '@mui/icons-material' import ClearIcon from '@mui/icons-material/Clear' import SaveIcon from '@mui/icons-material/Save' import WarningPopup from '../../components/WarningPopup.tsx' -import axios, { AxiosResponse } from 'axios' -import { User } from '../subjectsPage/AddChangeSubjectPage.tsx' // group interface export interface Group { @@ -184,21 +182,39 @@ export function GroupsPage() { await instance .get('/vakken/' + courseId) .then(async (response) => { - // This function fetches the names of the students in parallel const newStudentNames = new Map() - const studentPromises: Promise>[] = - response.data.studenten.map((id: number) => - instance.get('/gebruikers/' + id) - ) - const studentResponses = await axios.all(studentPromises) - - studentResponses.forEach((response) => { - const student: User = response.data - newStudentNames.set( - student.user, - student.first_name + ' ' + student.last_name - ) - }) + + for (const student of response.data.studenten) { + await instance + .get('/gebruikers/' + student) + .then((response) => { + newStudentNames.set( + student, + response.data.first_name + + ' ' + + response.data.last_name + ) + }) + .catch((error) => { + console.log(error) + }) + } + for (const student of response.data.studenten) { + await instance + .get('/gebruikers/' + student) + .then((response) => { + newStudentNames.set( + student, + response.data.first_name + + ' ' + + response.data.last_name + ) + console.log( + 'available names:' + + Array.from(newStudentNames.entries()) + ) + }) + } setStudentNames(() => newStudentNames) }) @@ -259,7 +275,7 @@ export function GroupsPage() { .catch((error) => { console.log(error) }) - }, [assignmentId, courseId]) + }, [assignmentId, courseId, newGroupSize, studentNames.size]) useEffect(() => { setAvailableStudents(() => @@ -271,7 +287,7 @@ export function GroupsPage() { ) ) setFilteredStudents(availableStudents) - }, [availableStudents, newGroups, studentNames]) + }, [newGroups, studentNames]) // Create new groups when the group size changes useEffect(() => { @@ -296,7 +312,6 @@ export function GroupsPage() { } }, [ assignmentId, - availableStudents, availableStudents.length, newGroupSize, newGroups.length, From b65475e3581c86655688f59d021d481d93281ea9 Mon Sep 17 00:00:00 2001 From: Ben De Meurichy Date: Sun, 19 May 2024 18:07:17 +0200 Subject: [PATCH 17/24] opnieuw performance omhoog gedaan --- .../src/pages/groupsPage/GroupsPage.tsx | 49 +++++++------------ 1 file changed, 17 insertions(+), 32 deletions(-) diff --git a/frontend/frontend/src/pages/groupsPage/GroupsPage.tsx b/frontend/frontend/src/pages/groupsPage/GroupsPage.tsx index 38707a4d..ff0bdcb7 100644 --- a/frontend/frontend/src/pages/groupsPage/GroupsPage.tsx +++ b/frontend/frontend/src/pages/groupsPage/GroupsPage.tsx @@ -30,6 +30,8 @@ import { Add } from '@mui/icons-material' import ClearIcon from '@mui/icons-material/Clear' import SaveIcon from '@mui/icons-material/Save' import WarningPopup from '../../components/WarningPopup.tsx' +import axios, { AxiosResponse } from 'axios' +import { User } from '../subjectsPage/AddChangeSubjectPage.tsx' // group interface export interface Group { @@ -182,39 +184,22 @@ export function GroupsPage() { await instance .get('/vakken/' + courseId) .then(async (response) => { + // This function fetches the names of the students in parallel const newStudentNames = new Map() - for (const student of response.data.studenten) { - await instance - .get('/gebruikers/' + student) - .then((response) => { - newStudentNames.set( - student, - response.data.first_name + - ' ' + - response.data.last_name - ) - }) - .catch((error) => { - console.log(error) - }) - } - for (const student of response.data.studenten) { - await instance - .get('/gebruikers/' + student) - .then((response) => { - newStudentNames.set( - student, - response.data.first_name + - ' ' + - response.data.last_name - ) - console.log( - 'available names:' + - Array.from(newStudentNames.entries()) - ) - }) - } + const studentPromises: Promise>[] = + response.data.studenten.map((id: number) => + instance.get('/gebruikers/' + id) + ) + const studentResponses = await axios.all(studentPromises) + + studentResponses.forEach((response) => { + const student: User = response.data + newStudentNames.set( + student.user, + student.first_name + ' ' + student.last_name + ) + }) setStudentNames(() => newStudentNames) }) @@ -275,7 +260,7 @@ export function GroupsPage() { .catch((error) => { console.log(error) }) - }, [assignmentId, courseId, newGroupSize, studentNames.size]) + }, [assignmentId, courseId]) useEffect(() => { setAvailableStudents(() => From ddca5ccb20ff44a814909e39e96fb3d7ba77389e Mon Sep 17 00:00:00 2001 From: elias Date: Sun, 19 May 2024 18:14:21 +0200 Subject: [PATCH 18/24] some minor changes --- frontend/frontend/src/components/CopyToClipboard.tsx | 11 ++++++----- frontend/frontend/src/components/Header.tsx | 1 + .../frontend/src/pages/subjectsPage/SubjectsPage.tsx | 1 + 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/frontend/frontend/src/components/CopyToClipboard.tsx b/frontend/frontend/src/components/CopyToClipboard.tsx index fdaf5818..2e3a9a03 100644 --- a/frontend/frontend/src/components/CopyToClipboard.tsx +++ b/frontend/frontend/src/components/CopyToClipboard.tsx @@ -1,8 +1,10 @@ import { useState } from 'react' +import { darken } from '@mui/system' import { Box, Collapse, Tooltip, Typography } from '@mui/material' -import Button from '@mui/material/Button' +import { Button } from './CustomComponents.tsx' import { AssignmentTurnedIn, ContentPaste } from '@mui/icons-material' import { t } from 'i18next' +import theme from "../Theme.ts"; interface CopyToClipboardProps { invitationLink: string @@ -42,13 +44,12 @@ export const CopyToClipboard = ({ invitationLink }: CopyToClipboardProps) => { > + - + {loading ? ( @@ -422,6 +421,7 @@ export function ProjectScoresPage() { )} + setOpenDeleteScoresPopup(true) diff --git a/frontend/frontend/src/pages/scoresPage/StudentScoreListItem.tsx b/frontend/frontend/src/pages/scoresPage/StudentScoreListItem.tsx index 0a6ac60a..d14c59cc 100644 --- a/frontend/frontend/src/pages/scoresPage/StudentScoreListItem.tsx +++ b/frontend/frontend/src/pages/scoresPage/StudentScoreListItem.tsx @@ -1,4 +1,4 @@ -import { Divider } from '../../components/CustomComponents.tsx' +import {Divider, EvenlySpacedRow} from '../../components/CustomComponents.tsx' import { CircularProgress, ListItemIcon, @@ -95,32 +95,20 @@ export function StudentScoreListItem({ return ( <> - + {/* Inner list item for displaying submission details */} - + {/* Content section */} <> {loading ? ( ) : ( + - )} + />, - {/* Score section */} - + />, + {lastSubmission ? ( <> - + @@ -153,9 +140,8 @@ export function StudentScoreListItem({ ) : ( )} - - {/* Display download icon */} - + , +
{lastSubmission ? ( @@ -172,7 +158,9 @@ export function StudentScoreListItem({ )}
-
+
]} + /> + )}
diff --git a/frontend/frontend/src/pages/scoresPage/StudentsView.tsx b/frontend/frontend/src/pages/scoresPage/StudentsView.tsx index 75457d0d..3058be90 100644 --- a/frontend/frontend/src/pages/scoresPage/StudentsView.tsx +++ b/frontend/frontend/src/pages/scoresPage/StudentsView.tsx @@ -1,4 +1,4 @@ -import { Divider } from '../../components/CustomComponents.tsx' +import {Divider, EvenlySpacedRow} from '../../components/CustomComponents.tsx' import { Box, Skeleton, Typography } from '@mui/material' import List from '@mui/material/List' import { StudentScoreListItem } from './StudentScoreListItem.tsx' @@ -116,29 +116,25 @@ export function StudentsView({ - <> + {t('group')} - + , {t('time')} - + , Score - + , Download - - + ]} + /> {/* Scrollable list of students */} From 4dc8e361261a610ec35e8b1f75ba79aae3e23c5c Mon Sep 17 00:00:00 2001 From: elias Date: Sun, 19 May 2024 20:43:47 +0200 Subject: [PATCH 22/24] done visuals --- .../src/components/CopyToClipboard.tsx | 7 +- .../src/components/CustomComponents.tsx | 14 +- .../src/components/DeadlineCalendar.tsx | 1 - frontend/frontend/src/i18n/en.ts | 2 - .../src/pages/groupsPage/ChooseGroup.tsx | 209 +++++------ .../pages/scoresPage/ProjectScoresPage.tsx | 21 +- .../pages/scoresPage/StudentScoreListItem.tsx | 130 +++---- .../src/pages/scoresPage/StudentsView.tsx | 30 +- .../subjectsPage/AddChangeSubjectPage.tsx | 326 +++++++++--------- .../src/pages/subjectsPage/SubjectsPage.tsx | 34 +- .../pages/submissionPage/SubmissionPage.tsx | 10 +- 11 files changed, 413 insertions(+), 371 deletions(-) diff --git a/frontend/frontend/src/components/CopyToClipboard.tsx b/frontend/frontend/src/components/CopyToClipboard.tsx index 2e3a9a03..80c021a1 100644 --- a/frontend/frontend/src/components/CopyToClipboard.tsx +++ b/frontend/frontend/src/components/CopyToClipboard.tsx @@ -4,7 +4,7 @@ import { Box, Collapse, Tooltip, Typography } from '@mui/material' import { Button } from './CustomComponents.tsx' import { AssignmentTurnedIn, ContentPaste } from '@mui/icons-material' import { t } from 'i18next' -import theme from "../Theme.ts"; +import theme from '../Theme.ts' interface CopyToClipboardProps { invitationLink: string @@ -57,7 +57,10 @@ export const CopyToClipboard = ({ invitationLink }: CopyToClipboardProps) => { padding: 0, gap: 1, '&:hover': { - backgroundColor: darken(theme.palette.secondary.main,0.2) + backgroundColor: darken( + theme.palette.secondary.main, + 0.2 + ), }, }} > diff --git a/frontend/frontend/src/components/CustomComponents.tsx b/frontend/frontend/src/components/CustomComponents.tsx index 09571153..f5bf4610 100644 --- a/frontend/frontend/src/components/CustomComponents.tsx +++ b/frontend/frontend/src/components/CustomComponents.tsx @@ -90,7 +90,7 @@ interface CustomDividerProps extends DividerProps { children?: ReactNode } -export const Divider = ({ children, ...props }: CustomCardProps) => { +export const Divider = ({ children, ...props }: CustomDividerProps) => { return ( { ) } - interface EvenlySpacedRowProps { items: ReactNode[] } @@ -116,10 +115,13 @@ export const EvenlySpacedRow = ({ items }: EvenlySpacedRowProps) => { - @@ -56,10 +58,7 @@ function joinLeaveButton( } return ( <> - @@ -208,25 +207,34 @@ export function ChooseGroup() { - - {t('group_number')} - , - - {t('members')} - , - ]} + + {t('group_number')} + , + + {t('members')} + , + , + ]} /> - + - , - - {loading ? ( - - {t( - 'members_loading' - )} - - ) : ( - <> - {group - .studenten - .length > - 0 ? ( - group.studenten.map( - ( - studentid - ) => { - const student = - studenten[ - studentid - ] - if ( - student - ) { - console.log( - 'Student:', - student - ) - return ( - - {student.first_name + - ' ' + - student.last_name} - - ) - } - return null - } - ) - ) : ( + , + + {loading ? ( {t( - 'no_members_yet' + 'members_loading' )} + ) : ( + <> + {group + .studenten + .length > + 0 ? ( + group.studenten.map( + ( + studentid + ) => { + const student = + studenten[ + studentid + ] + if ( + student + ) { + console.log( + 'Student:', + student + ) + return ( + + {student.first_name + + ' ' + + student.last_name} + + ) + } + return null + } + ) + ) : ( + + {t( + 'no_members_yet' + )} + + )} + )} - - )} - , - <> - {joinLeaveButton( - user != - undefined - ? group.studenten.includes( - user.user - ) - : false, - handleJoin, - handleLeave - )} - ]}/> + , + <> + {joinLeaveButton( + user != + undefined + ? group.studenten.includes( + user.user + ) + : false, + handleJoin, + handleLeave + )} + , + ]} + /> - ) })} diff --git a/frontend/frontend/src/pages/scoresPage/ProjectScoresPage.tsx b/frontend/frontend/src/pages/scoresPage/ProjectScoresPage.tsx index 0397eea4..9f5d4723 100644 --- a/frontend/frontend/src/pages/scoresPage/ProjectScoresPage.tsx +++ b/frontend/frontend/src/pages/scoresPage/ProjectScoresPage.tsx @@ -1,5 +1,5 @@ import { Header } from '../../components/Header' -import {Button, Card, SecondaryButton} from '../../components/CustomComponents.tsx' +import { Card, SecondaryButton } from '../../components/CustomComponents.tsx' import { Box, CircularProgress, @@ -372,11 +372,15 @@ export function ProjectScoresPage() { spacing={2} marginY={6} > - + {t('export_submissions')} - + {t('upload_scores')} {loading ? ( @@ -421,7 +430,7 @@ export function ProjectScoresPage() {
)} - + setOpenDeleteScoresPopup(true) diff --git a/frontend/frontend/src/pages/scoresPage/StudentScoreListItem.tsx b/frontend/frontend/src/pages/scoresPage/StudentScoreListItem.tsx index d14c59cc..92dcc299 100644 --- a/frontend/frontend/src/pages/scoresPage/StudentScoreListItem.tsx +++ b/frontend/frontend/src/pages/scoresPage/StudentScoreListItem.tsx @@ -1,4 +1,4 @@ -import {Divider, EvenlySpacedRow} from '../../components/CustomComponents.tsx' +import { Divider, EvenlySpacedRow } from '../../components/CustomComponents.tsx' import { CircularProgress, ListItemIcon, @@ -103,63 +103,77 @@ export function StudentScoreListItem({ {loading ? ( ) : ( - , - , - - {lastSubmission ? ( - <> - - - changeScore( - parseInt(event.target.value) - ) - } - variant="standard" - size="small" - /> - - - - ) : ( - - )} - , - - -
- {lastSubmission ? ( - - ) : ( - - )} -
-
-
]} - /> + , + , + + {lastSubmission ? ( + <> + + + changeScore( + parseInt( + event.target + .value + ) + ) + } + variant="standard" + size="small" + /> + + + + ) : ( + + )} + , + + +
+ {lastSubmission ? ( + + ) : ( + + )} +
+
+
, + ]} + /> )}
diff --git a/frontend/frontend/src/pages/scoresPage/StudentsView.tsx b/frontend/frontend/src/pages/scoresPage/StudentsView.tsx index 3058be90..c64c76fa 100644 --- a/frontend/frontend/src/pages/scoresPage/StudentsView.tsx +++ b/frontend/frontend/src/pages/scoresPage/StudentsView.tsx @@ -1,4 +1,4 @@ -import {Divider, EvenlySpacedRow} from '../../components/CustomComponents.tsx' +import { Divider, EvenlySpacedRow } from '../../components/CustomComponents.tsx' import { Box, Skeleton, Typography } from '@mui/material' import List from '@mui/material/List' import { StudentScoreListItem } from './StudentScoreListItem.tsx' @@ -121,19 +121,21 @@ export function StudentsView({ padding: 3, }} > - - {t('group')} - , - - {t('time')} - , - - Score - , - - Download - ]} + + {t('group')} + , + + {t('time')} + , + + Score + , + + Download + , + ]} /> diff --git a/frontend/frontend/src/pages/subjectsPage/AddChangeSubjectPage.tsx b/frontend/frontend/src/pages/subjectsPage/AddChangeSubjectPage.tsx index 946cccde..b86972a8 100644 --- a/frontend/frontend/src/pages/subjectsPage/AddChangeSubjectPage.tsx +++ b/frontend/frontend/src/pages/subjectsPage/AddChangeSubjectPage.tsx @@ -1,9 +1,13 @@ -import { Divider, Card } from '../../components/CustomComponents.tsx' +import { + Divider, + Card, + SecondaryButton, + EvenlySpacedRow, +} from '../../components/CustomComponents.tsx' import { Box, IconButton, ListItem, - ListItemButton, ListItemText, Skeleton, Stack, @@ -48,11 +52,7 @@ function UserList( :not(style)': { - marginBottom: '8px', - width: '99vw', - }, - minHeight: '20vh', + minHeight: '30vh', maxHeight: '30vh', overflowY: 'auto', }} @@ -80,66 +80,55 @@ function UserList( } return ( <> - - - - - - - - - - - - + + , + + + + + + , + ]} + /> + + ) })} @@ -175,9 +164,9 @@ function UploadPart( /> - + @@ -623,7 +611,8 @@ export function AddChangeSubjectPage() { ) : ( setTitle( event.target.value @@ -634,106 +623,117 @@ export function AddChangeSubjectPage() { )} - + - - - - {t('students')} - + + + + + + + {t('students')} + + + + + {UserList( + loading, + students, + setSelectedStudent, + setOpenStudent + )} + + + + {UploadPart( + studentFile, + handleStudentFileChange, + setEmailStudent, + handleAddStudent, + t('upload_students') + )} + + {DialogWindow( + handleCloseStudent, + openStudent, + handleRemoveStudent, + t('delete_student') + )} + - - {UserList( - loading, - students, - setSelectedStudent, - setOpenStudent - )} + + + + + + {t('teachers')} + + + + + {UserList( + loading, + teachers, + setSelectedTeacher, + setOpenTeacher + )} + + + + {UploadPart( + teacherFile, + handleTeacherFileChange, + setEmailTeacher, + handleAddTeacher, + t('upload_teachers') + )} + + + {DialogWindow( + handleCloseTeacher, + openTeacher, + handleRemoveTeacher, + t('delete_teacher') + )} + - - - {UploadPart( - studentFile, - handleStudentFileChange, - setEmailStudent, - handleAddStudent, - t('upload_students') - )} - - - {DialogWindow( - handleCloseStudent, - openStudent, - handleRemoveStudent, - t('delete_student') - )} - - - - - {t('teachers')} - - - - {UserList( - loading, - teachers, - setSelectedTeacher, - setOpenTeacher - )} - - - - {UploadPart( - teacherFile, - handleTeacherFileChange, - setEmailTeacher, - handleAddTeacher, - t('upload_teachers') - )} - - - {DialogWindow( - handleCloseTeacher, - openTeacher, - handleRemoveTeacher, - t('delete_teacher') - )} + diff --git a/frontend/frontend/src/pages/subjectsPage/SubjectsPage.tsx b/frontend/frontend/src/pages/subjectsPage/SubjectsPage.tsx index b0b97b3c..1b1715c5 100644 --- a/frontend/frontend/src/pages/subjectsPage/SubjectsPage.tsx +++ b/frontend/frontend/src/pages/subjectsPage/SubjectsPage.tsx @@ -1,11 +1,5 @@ import { Header } from '../../components/Header' -import { - Box, - CircularProgress, - Grid, - IconButton, - Stack, -} from '@mui/material' +import { Box, CircularProgress, Grid, IconButton, Stack } from '@mui/material' import TabSwitcher from '../../components/TabSwitcher.tsx' import { ProjectsView } from './ProjectsView.tsx' import { useNavigate, useParams } from 'react-router-dom' @@ -331,19 +325,19 @@ export function SubjectsPage() { '/accept_invitation' } /> - - - + + + ) : ( - {submission?.status === SubmissionStatus.PENDING From f0f9c53cd0b53fc55c2c76de7a9dfa5749fedd60 Mon Sep 17 00:00:00 2001 From: elias Date: Sun, 19 May 2024 20:51:22 +0200 Subject: [PATCH 23/24] small tweek --- .../frontend/src/pages/subjectsPage/AddChangeSubjectPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/frontend/src/pages/subjectsPage/AddChangeSubjectPage.tsx b/frontend/frontend/src/pages/subjectsPage/AddChangeSubjectPage.tsx index b86972a8..01c515b4 100644 --- a/frontend/frontend/src/pages/subjectsPage/AddChangeSubjectPage.tsx +++ b/frontend/frontend/src/pages/subjectsPage/AddChangeSubjectPage.tsx @@ -200,6 +200,7 @@ function DialogWindow( + @@ -724,7 +725,6 @@ export function AddChangeSubjectPage() { t('upload_teachers') )} - {DialogWindow( handleCloseTeacher, openTeacher, From 07c9ce59adaea55bb91f1902c61cda790d1b8cad Mon Sep 17 00:00:00 2001 From: Mathis De Witte Date: Sun, 19 May 2024 21:33:10 +0200 Subject: [PATCH 24/24] remove double import --- .../frontend/src/pages/subjectsPage/AddChangeSubjectPage.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/frontend/src/pages/subjectsPage/AddChangeSubjectPage.tsx b/frontend/frontend/src/pages/subjectsPage/AddChangeSubjectPage.tsx index 7328adaf..b86c6118 100644 --- a/frontend/frontend/src/pages/subjectsPage/AddChangeSubjectPage.tsx +++ b/frontend/frontend/src/pages/subjectsPage/AddChangeSubjectPage.tsx @@ -7,7 +7,6 @@ import { import { Box, - CircularProgress, IconButton, ListItem, ListItemText,