Skip to content

Prepared closest events and announcements sections on dashboard #86

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/components/shared/appBar/AppBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ function AppBar() {
position: 'sticky',
background: 'white',
top: 0,
zIndex: '999',
}}
>
<Box className="AppBarBox">
Expand Down
13 changes: 0 additions & 13 deletions src/components/viewsComponents/dashboard/Dashboard.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,4 @@
grid-template-columns: min-content auto;
gap: 16px;
margin-bottom: 16px;

.AvatarBox {
display: grid;
grid-template-columns: 1fr;
justify-items: center;
gap: 1rem;
padding: 2rem;

}

@media (max-width: '700px') {
grid-template-columns: 1fr;
}
}
85 changes: 28 additions & 57 deletions src/components/viewsComponents/dashboard/Dashboard.tsx
Original file line number Diff line number Diff line change
@@ -1,83 +1,54 @@
import { useSelector } from 'react-redux';
import { useNavigate } from 'react-router-dom';
import { Box, Button, Paper, Typography, useMediaQuery } from '@mui/material';
import { Box, useMediaQuery } from '@mui/material';
import CenteredLoader from 'components/shared/centeredLoader/CenteredLoader';
import TodoListDrawer from 'components/shared/todoListDrawer/TodoListDrawer';
import _ from 'lodash';
import { useGetStudentGradesQuery } from 'redux/apiSlices/academics/Grades.Api.Slice';
import { selectId, useGetLoggedAccountBasicDataQuery } from 'redux/apiSlices/loggedAccount/LoggedAccount.Api.Slice';
import { calculateAverageGrade } from '../grades/elements/gradesInformationBoxes/GradesInformationBoxes';
import GradesDonutChart from './elements/GradesDonutChart';
import Announcements from './elements/Announcements';
import ClosestEvents from './elements/ClosestEvents';
import GradesSection from './elements/GradesSection';
import type { IGetStudentGradesQueryParams } from 'contract/slices/academics/Grades.Interfaces';
import './Dashboard.scss';

function Dashboard() {
const navigate = useNavigate();
const studentId = useSelector(selectId);
const isMobile = useMediaQuery('(max-width: 500px)');
const maxDrawerWidth = isMobile ? 280 : 450;
const { data } = useGetLoggedAccountBasicDataQuery();

const { data: userData, isFetching: isFetchingUserData } = useGetLoggedAccountBasicDataQuery();

const studentId = useSelector(selectId);
const initialQueryParams: IGetStudentGradesQueryParams = { studentId: studentId! };
const { data: grades, isFetching } = useGetStudentGradesQuery(initialQueryParams, { skip: !studentId });
const { data: grades, isFetching: isFetchingGrades } = useGetStudentGradesQuery(initialQueryParams, {
skip: !studentId,
});

const isFetching = isFetchingUserData || isFetchingGrades;

if (isFetching || !data) {
if (isFetching || !userData) {
return <CenteredLoader />;
}

const averageGrade = calculateAverageGrade(grades ?? []);
const gradeGroups = _.groupBy(grades, 'grade');
const groupedData = [
{ grade: '2', count: gradeGroups[2]?.length ?? 0, fill: '#c40101' },
{ grade: '3', count: gradeGroups[3]?.length ?? 0, fill: '#ff9800' },
{ grade: '4', count: gradeGroups[4]?.length ?? 0, fill: '#2196f3' },
{ grade: '5', count: gradeGroups[5]?.length ?? 0, fill: '#09750d' },
];

return (
<Box>
<Paper
<Box sx={{ p: 5 }}>
<Box
sx={{
display: 'flex',
flexWrap: 'wrap',
gap: 2,
alignContent: 'center',
p: 4,
width: 'fit-content',

'@media (max-width: 650px)': {
px: 2,
},
gap: 6,
}}
>
<Box
sx={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
gap: 3,
flex: 1,
minWidth: '180px',
}}
>
<Typography variant="h4" color="#524e61" fontWeight="bold">
Hi, <span style={{ whiteSpace: 'nowrap' }}> {`${data.name} ${data.surname}!`}</span>
</Typography>
<Typography variant="body1" color="text.secondary">
Check your performance stats <br /> to make sure you are on track <br /> with your academic goals!
</Typography>
<Button
variant="text"
sx={{ whiteSpace: 'nowrap', maxWidth: '100px' }}
onClick={() => {
navigate('/postAuth/academics/grades');
}}
>
See all Grades
</Button>
<Box>
<GradesSection grades={grades} userData={userData} />
</Box>
<Box>
<ClosestEvents />
</Box>
<GradesDonutChart groupedData={groupedData} averageGrade={averageGrade} />
</Paper>
<Typography variant="h5"> Due missing data, content will cooming soon!</Typography>

<Box>
<Announcements />
</Box>
</Box>

<TodoListDrawer maxDrawerWidth={maxDrawerWidth} />
</Box>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import React from 'react';
import CalendarMonthIcon from '@mui/icons-material/CalendarMonth';
import { Typography, List, ListItem, Paper, Box } from '@mui/material';

interface IMessage {
id: number;
title: string;
body: string;
date: string;
}

const messages: IMessage[] = [
{
id: 1,
title: 'Welcome to the Semester!',
body: 'We hope you have a great start to the semester. Remember to check your schedules and prepare for the first week of classes.',
date: '2024-01-15',
},
{
id: 2,
title: 'Library System Maintenance',
body: 'The library system will be undergoing maintenance on January 20th from 8 PM to 12 AM. Please plan accordingly.',
date: '2024-01-18',
},
{
id: 3,
title: 'Course Enrollment Deadline',
body: 'The last date to add or drop courses for this semester is January 25th. Make sure to finalize your schedules.',
date: '2024-01-22',
},
];

const Messages: React.FC = () => {
return (
<Paper
sx={{
display: 'flex',
flexDirection: 'column',
gap: 2,
alignContent: 'center',
p: 4,
}}
>
<Typography variant="h5" color="#524e61" fontWeight="bold" gutterBottom>
Latest Messages from Administration
</Typography>
<List>
{messages.map(message => (
<ListItem
key={message.id}
sx={{
borderBottom: '1px solid #ddd',
paddingLeft: 0,
alignItems: 'flex-start',
':last-child': {
borderBottom: 'none',
},
flexDirection: 'column',
gap: 1,
}}
>
<Typography variant="subtitle1" component="div" sx={{ fontWeight: 'bold' }}>
{message.title}
</Typography>
<Typography variant="body2" color="text.secondary" sx={{ color: '#555' }} component="div">
{message.body}
</Typography>
<Box
sx={{
display: 'flex',
alignItems: 'center',
gap: 0.5,
color: '#888',
}}
>
<CalendarMonthIcon fontSize="small" />
<Typography variant="caption" component="span">
{new Date(message.date).toLocaleDateString()}
</Typography>
</Box>
</ListItem>
))}
</List>
</Paper>
);
};

export default Messages;
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import React from 'react';
import EventIcon from '@mui/icons-material/Event';
import { Typography, List, ListItem, Paper, Box } from '@mui/material';

const calculateFutureDate = (daysToAdd: number): Date => {
const today = new Date();
today.setDate(today.getDate() + daysToAdd);
return today;
};

const events = [
{ id: 1, title: 'Orientation Day', date: calculateFutureDate(2) },
{ id: 2, title: 'Midterm Exams', date: calculateFutureDate(30) },
{ id: 3, title: 'Career Fair', date: calculateFutureDate(50) },
];

const ClosestEvents: React.FC = () => {
return (
<Paper
sx={{
display: 'flex',
flexDirection: 'column',
gap: 1,
p: 2,
width: 'fit-content',
minHeight: '289px',
}}
>
<Typography variant="h5" color="#524e61" fontWeight="bold">
Closest Upcoming Events
</Typography>
<List>
{events.map(event => (
<ListItem
key={event.id}
sx={{
borderBottom: '1px solid #ddd',
paddingLeft: 0,
alignItems: 'flex-start',
':last-child': {
borderBottom: 'none',
},
flexDirection: 'column',
}}
>
<Typography variant="subtitle1" component="div" sx={{ fontWeight: 'bold' }}>
{event.title}
</Typography>
<Box
sx={{
display: 'flex',
alignItems: 'center',
gap: 0.5,
color: '#888',
}}
>
<EventIcon fontSize="small" />
<Typography variant="caption" component="span">
{new Date(event.date).toLocaleDateString()}
</Typography>
</Box>
</ListItem>
))}
</List>
</Paper>
);
};

export default ClosestEvents;
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { useNavigate } from 'react-router-dom';
import { Typography, Paper, Box, Button } from '@mui/material';
import { calculateAverageGrade } from 'components/viewsComponents/grades/elements/gradesInformationBoxes/GradesInformationBoxes';
import _ from 'lodash';
import GradesDonutChart from './GradesDonutChart';
import type { IGrade } from 'contract/interfaces/academics/Academics';
import type { IGetLoggedAccountBasicDataTransformedReponse } from 'contract/slices/loggedAccount/LoggedAccount';

interface GradesSectionProps {
grades?: IGrade[];
userData: IGetLoggedAccountBasicDataTransformedReponse;
}

const GradesSection: React.FC<GradesSectionProps> = ({ grades, userData }) => {
const navigate = useNavigate();

const averageGrade = calculateAverageGrade(grades ?? []);
const gradeGroups = _.groupBy(grades, 'grade');
const groupedData = [
{ grade: '2', count: gradeGroups[2]?.length ?? 0, fill: '#c40101' },
{ grade: '3', count: gradeGroups[3]?.length ?? 0, fill: '#ff9800' },
{ grade: '4', count: gradeGroups[4]?.length ?? 0, fill: '#2196f3' },
{ grade: '5', count: gradeGroups[5]?.length ?? 0, fill: '#09750d' },
];

return (
<Paper
sx={{
display: 'flex',
flexWrap: 'wrap',
gap: 2,
p: 4,
width: 'fit-content',
}}
>
<Box
sx={{
display: 'flex',
flexDirection: 'column',
gap: 3,
flex: 1,
minWidth: '180px',
}}
>
<Typography variant="h5" color="#524e61" fontWeight="bold">
Hi, <span>{`${userData.name} ${userData.surname}!`}</span>
</Typography>
<Typography variant="body1" color="text.secondary">
Check your performance stats <br /> to make sure you are on track <br /> with your academic goals!
</Typography>
<Button
variant="text"
sx={{ whiteSpace: 'nowrap', maxWidth: '100px' }}
onClick={() => {
navigate('/postAuth/academics/grades');
}}
>
See all Grades
</Button>
</Box>
<GradesDonutChart groupedData={groupedData} averageGrade={averageGrade} />
</Paper>
);
};

export default GradesSection;
Loading