Skip to content

Commit

Permalink
Homepage student + landing page (#194)
Browse files Browse the repository at this point in the history
Homepages added
  • Loading branch information
warreprovoost authored Apr 18, 2024
1 parent f2de32a commit 2630299
Show file tree
Hide file tree
Showing 10 changed files with 535 additions and 18 deletions.
Binary file added frontend/public/img/logo_app.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 18 additions & 2 deletions frontend/public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
"home": {
"home": "Home",
"tag": "en",
"homepage": "Homepage"
"homepage": "Homepage",
"welcomeDescription": "Welcome to Peristerónas, the online submission platform of UGent",
"login": "Login"
},
"courseForm": {
"courseName": "Course Name",
Expand Down Expand Up @@ -79,5 +81,19 @@
"noRegexPlaceholder": "No regex added yet",
"clearSelected": "Clear Selection",
"faultySubmission": "Some fields were left open or there is no valid runner/file combination"
},
"student" : {
"myProjects": "My Projects",
"myCourses": "My Courses",
"deadlines": "Past deadlines",
"last_submission" : "Last submission",
"course": "Course",
"SUCCESS": "Success",
"FAIL": "Fail",
"deadlinesOnDay": "Deadlines on: ",
"noDeadline": "No deadlines",
"no_submission_yet" : "No submission yet",
"loading": "Loading...",
"no_projects": "There are no projects here."
}
}
}
23 changes: 18 additions & 5 deletions frontend/public/locales/nl/translation.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
{
"home": {
"title": "Homepagina"
},
"header": {
"myProjects": "Mijn Projecten",
"myCourses": "Mijn Vakken",
Expand All @@ -12,16 +9,32 @@
"projectUploadForm": "Project uploaden"
},
"home": {
"login": "Aanmelden",
"home": "Home",
"tag": "nl",
"homepage": "Homepage"
"homepage": "Homepagina",
"welcomeDescription": "Welkom bij Peristerónas, het online indieningsplatform van UGent",
"login": "Aanmelden"
},
"courseForm": {
"courseName": "Vak Naam",
"submit": "Opslaan",
"emptyCourseNameError": "Vak naam mag niet leeg zijn"
},
"student": {
"myProjects": "Mijn Projecten",
"myCourses": "Mijn Vakken",
"deadlines": "Verlopen Deadlines",
"course": "Vak",
"last_submission": "Laatste indiening",
"SUCCESS": "Geslaagd",
"FAIL": "Gefaald",
"deadlinesOnDay": "Deadlines op: ",
"noDeadline": "Geen deadlines",
"no_submission_yet" : "Nog geen indiening",
"loading": "Laden...",
"no_projects": "Er zijn hier geen projecten."

},
"projectForm": {
"projectTitle": "Titel",
"projectDescription": "Beschrijving",
Expand Down
7 changes: 4 additions & 3 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { Route, RouterProvider, createBrowserRouter, createRoutesFromElements } from "react-router-dom";
import Layout from "./components/Header/Layout";
import Home from "./pages/home/Home";
import LanguagePath from "./components/LanguagePath";
import ProjectView from "./pages/project/projectView/ProjectView";
import { ErrorBoundary } from "./pages/error/ErrorBoundary.tsx";
import ProjectCreateHome from "./pages/create_project/ProjectCreateHome.tsx";
import {fetchProjectPage} from "./pages/project/FetchProjects.tsx";
import HomePages from "./pages/home/HomePages.tsx";

const router = createBrowserRouter(
createRoutesFromElements(
<Route path="/" element={<Layout />} errorElement={<ErrorBoundary />}>
<Route index element={<Home />} />
<Route index element={<HomePages />} loader={fetchProjectPage}/>
<Route path=":lang" element={<LanguagePath/>}>
<Route path="home" element={<Home />} />
<Route path="home" element={<HomePages />} loader={fetchProjectPage} />
<Route path="project" >
<Route path=":projectId" element={<ProjectView />}/>
</Route>
Expand Down
50 changes: 42 additions & 8 deletions frontend/src/pages/home/Home.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,50 @@
import { useTranslation } from "react-i18next";
import { Title } from "../../components/Header/Title";
import { Button, Container, Typography, Box } from "@mui/material";
import {Link } from "react-router-dom";

/**
* This component is the home page component that will be rendered when on the index route.
* @returns - The home page component
*/
export default function Home() {
const { t } = useTranslation("translation", { keyPrefix: "home" });
const { t } = useTranslation('translation', { keyPrefix: 'home' });
const login_redirect:string =import.meta.env.VITE_LOGIN_LINK
return (
<>
<Title title={t('title')} />
<div>
</div>
</>
);
<Container maxWidth="sm">
<Box
sx={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
height: '100vh',
textAlign: 'center',
gap: 3,
}}
>
<Box component="img"src="/img/logo_ugent.png" alt="University Logo"
sx={{ width: 100, height: 100 }} />

<Typography variant="h2" component="h1" gutterBottom >
<Box
component="img"
src="/img/logo_app.png"
alt="University Logo"
sx={{
position: 'relative',
top: '14px',
width: 90,
height: 90,
}}
/>
Peristerónas
</Typography>
<Typography variant="h6" component="p" >
{t('welcomeDescription', 'Welcome to Peristeronas.')}
</Typography>
<Button variant="contained" color="primary" size="large" component={Link} to={login_redirect}>
{t('login', 'Login')}
</Button>
</Box>
</Container> );
}
197 changes: 197 additions & 0 deletions frontend/src/pages/home/HomePage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
import { useTranslation } from "react-i18next";
import {Card, CardContent, Typography, Grid, Container, Badge} from '@mui/material';
import { DateCalendar } from '@mui/x-date-pickers/DateCalendar';
import {DayCalendarSkeleton, LocalizationProvider} from '@mui/x-date-pickers';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import React, {useState} from 'react';
import dayjs, {Dayjs} from "dayjs";
import { PickersDay, PickersDayProps } from '@mui/x-date-pickers/PickersDay';
import {ProjectDeadlineCard} from "../project/projectDeadline/ProjectDeadlineCard.tsx";
import {ProjectDeadline} from "../project/projectDeadline/ProjectDeadline.tsx";
import {useLoaderData} from "react-router-dom";

interface DeadlineInfoProps {
selectedDay: Dayjs;
deadlines: ProjectDeadline[];
}

type ExtendedPickersDayProps = PickersDayProps<Dayjs> & { highlightedDays?: number[] };

/**
* Displays the deadlines on a given day
* @param selectedDay - The day of interest
* @param deadlines - All the deadlines to consider
* @returns Element
*/
const DeadlineInfo: React.FC<DeadlineInfoProps> = ({ selectedDay, deadlines }) => {
const { t } = useTranslation('translation', { keyPrefix: 'student' });
const deadlinesOnSelectedDay = deadlines.filter(
project => (project.deadline && dayjs(project.deadline).isSame(selectedDay, 'day'))
);
//list of the corresponding assignment
return (
<div>
{deadlinesOnSelectedDay.length === 0 ? (
<Card style={{margin: '10px 0'}}>
<CardContent>
<Typography variant="body1">
{t('noDeadline')}
</Typography>
</CardContent>
</Card>
) : <ProjectDeadlineCard deadlines={deadlinesOnSelectedDay}/>}
</div>
);
};

/**
*
* @param props - The day and the deadlines
* @returns - The ServerDay component that displays a badge for specific days
*/
function ServerDay(props: PickersDayProps<Dayjs> & { highlightedDays?: number[] }) {
const { highlightedDays = [], day, outsideCurrentMonth, ...other } = props;

const isSelected =
!props.outsideCurrentMonth && highlightedDays.indexOf(props.day.date()) >= 0;

return (
<Badge
key={props.day.toString()}
overlap="circular"
badgeContent={isSelected ? '🔴' : undefined}
sx={{
'.MuiBadge-badge': {
fontSize: '0.5em',
top: 8,
right: 8,
},
}}
>
<PickersDay {...other} outsideCurrentMonth={outsideCurrentMonth} day={day} />
</Badge>
);
}
const handleMonthChange =(
date: Dayjs,
projects:ProjectDeadline[],
setHighlightedDays: React.Dispatch<React.SetStateAction<number[]>>,
) => {

setHighlightedDays([]);
// projects are now only fetched on page load
const hDays:number[] = []
projects.map((project, ) => {
if(project.deadline && project.deadline.getMonth() == date.month() && project.deadline.getFullYear() == date.year()){
hDays.push(project.deadline.getDate())
}

}
);
setHighlightedDays(hDays)

};

/**
* This component is the home page component that will be rendered when on the index route.
* @returns - The home page component
*/
export default function HomePage() {
const { t } = useTranslation('translation', { keyPrefix: 'student' });

const [highlightedDays, setHighlightedDays] = React.useState<number[]>([]);

const [selectedDay, setSelectedDay] = useState<Dayjs>(dayjs(Date.now()));
const loader = useLoaderData() as {
projects: ProjectDeadline[],
me: string
}
const projects = loader.projects

// Update selectedDay state when a day is selected
const handleDaySelect = (day: Dayjs) => {
setSelectedDay(day);
};
const futureProjects = projects
.filter((p) => (p.deadline && dayjs(dayjs()).isBefore(p.deadline)))
.sort((a, b) => dayjs(a.deadline).diff(dayjs(b.deadline)))
.slice(0, 3) // only show the first 3

const pastDeadlines = projects
.filter((p) => p.deadline && (dayjs()).isAfter(p.deadline))
.sort((a, b) => dayjs(b.deadline).diff(dayjs(a.deadline)))
.slice(0, 3) // only show the first 3
const noDeadlineProject = projects.filter((p) => p.deadline === undefined)
return (
<Container style={{ paddingTop: '50px' }}>
<Grid container spacing={2} wrap="nowrap">
<Grid item xs={6}>
<Card>
<CardContent>
<Typography variant="body1">
{t('myProjects')}
</Typography>
{futureProjects.length + noDeadlineProject.length > 0? (
<>
<ProjectDeadlineCard deadlines={futureProjects} />
<ProjectDeadlineCard deadlines={noDeadlineProject}/>
</>
) : (
<Typography variant="body1">
{t('no_projects')}
</Typography>
)}
</CardContent>
</Card>
</Grid>

<Grid item xs={6}>
<Card>

<CardContent>
<Typography variant="body1">
{t('deadlines')}
</Typography>
{pastDeadlines.length > 0 ? (
<ProjectDeadlineCard deadlines={pastDeadlines} />
) : (
<Typography variant="body1">
{t('no_projects')}
</Typography>
)}
</CardContent>
</Card>
</Grid>

<Grid item xs={6}>
<Card>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<DateCalendar
value={selectedDay}
onMonthChange={(date: Dayjs) => { handleMonthChange(date, projects, setHighlightedDays) }}
onChange={handleDaySelect}
renderLoading={() => <DayCalendarSkeleton />}
slots={{
day: ServerDay,
}}
slotProps={{
day: {
highlightedDays,
} as ExtendedPickersDayProps,
}}
/>
</LocalizationProvider>
<CardContent>
<Typography variant="body2">
{t('deadlinesOnDay')} {selectedDay.format('MMMM D, YYYY')}
</Typography>
<DeadlineInfo selectedDay={selectedDay} deadlines={projects} />
</CardContent>

</Card>
</Grid>

</Grid>
</Container>
);
}
21 changes: 21 additions & 0 deletions frontend/src/pages/home/HomePages.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import HomePage from './HomePage.tsx';
import Home from "./Home.tsx";
import {useLoaderData} from "react-router-dom";
import {ProjectDeadline} from "../project/projectDeadline/ProjectDeadline.tsx";

/**
* Gives the requested home page based on the login status
* @returns - The home page component
*/
export default function HomePages() {
const loader = useLoaderData() as {
projects: ProjectDeadline[],
me: string
}
const me = loader.me
if (me === 'UNKNOWN') {
return <Home />;
} else {
return <HomePage />;
}
}
Loading

0 comments on commit 2630299

Please sign in to comment.