Skip to content
This repository has been archived by the owner on May 24, 2022. It is now read-only.

Commit

Permalink
Merge pull request #426 from SELab-2/inactive-edition-disable-buttons
Browse files Browse the repository at this point in the history
Disable some UI elements when edition is not active
  • Loading branch information
MaartenS11 authored May 22, 2022
2 parents 6e5b340 + 2b6666a commit 5e276e4
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 14 deletions.
23 changes: 18 additions & 5 deletions frontend/components/projects/ProjectTile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type ProjectProp = {
projectInput: ProjectBase;
refreshProjects: () => void;
conflictStudents: UUID[];
editionActive: boolean;
};

type UserProp = {
Expand All @@ -53,6 +54,7 @@ type AssignmentProp = {
setAssignmentId: (assignmentId: UUID) => void;
setRemoveStudentName: (removeStudentName: string) => void;
conflictStudents: UUID[];
editionActive: boolean;
};

/**
Expand Down Expand Up @@ -283,6 +285,7 @@ const ProjectTile: React.FC<ProjectProp> = ({
projectInput,
refreshProjects,
conflictStudents,
editionActive,
}: ProjectProp) => {
const router = useRouter();
const [user] = useUser();
Expand Down Expand Up @@ -388,6 +391,8 @@ const ProjectTile: React.FC<ProjectProp> = ({
() => ({
accept: ItemTypes.STUDENTTILE,
canDrop: (item) => {
if (!editionActive) return false;

return !myProject.assignments
.map((assignment) => assignment.student.id)
.includes((item as Student).id);
Expand All @@ -401,7 +406,7 @@ const ProjectTile: React.FC<ProjectProp> = ({
canDrop: monitor.canDrop(),
}),
}),
[myProject]
[myProject, editionActive]
);

const refresh = () => {
Expand Down Expand Up @@ -450,9 +455,12 @@ const ProjectTile: React.FC<ProjectProp> = ({
<p className="inline text-lg font-bold">
{myProject.name}
<i
className={`${
user.role == UserRole.Admin ? 'visible' : 'hidden'
} i-inline inline pl-2 text-xl opacity-20 hover:cursor-pointer`}
className={
`${
user.role == UserRole.Admin ? 'visible' : 'hidden'
} i-inline inline pl-2 text-xl opacity-20 hover:cursor-pointer ` +
(editionActive ? 'visible' : 'hidden')
}
onClick={() => setShowEditProject(true)}
>
{edit_icon}
Expand Down Expand Up @@ -487,6 +495,7 @@ const ProjectTile: React.FC<ProjectProp> = ({
setAssignmentId={setAssignmentId}
setRemoveStudentName={setRemoveStudentName}
conflictStudents={conflictStudents}
editionActive={editionActive}
/>
))}
</div>
Expand Down Expand Up @@ -784,6 +793,7 @@ const ProjectAssignmentsList: React.FC<AssignmentProp> = ({
setOpenUnassignment,
setRemoveStudentName,
conflictStudents,
editionActive,
}: AssignmentProp) => {
return (
<div className="flex flex-row justify-between pb-4">
Expand Down Expand Up @@ -825,7 +835,10 @@ const ProjectAssignmentsList: React.FC<AssignmentProp> = ({
);
setOpenUnassignment(true);
}}
className="icon-xcircle-red text-2xl hover:cursor-pointer"
className={
'icon-xcircle-red text-2xl hover:cursor-pointer ' +
(editionActive ? 'visible block' : 'hidden')
}
>
{xmark_circle}
</i>
Expand Down
17 changes: 15 additions & 2 deletions frontend/components/student/StudentView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,12 @@ import {
convertStudentBaseList,
convertStudentFullToList,
} from '../../lib/conversionUtils';
import { getUrlList, getUrlMap, parseError } from '../../lib/requestUtils';
import {
fetchEditionState,
getUrlList,
getUrlMap,
parseError,
} from '../../lib/requestUtils';
import { NextRouter } from 'next/dist/client/router';
import { useRouter } from 'next/router';
import { axiosAuthenticated } from '../../lib/axios';
Expand Down Expand Up @@ -306,10 +311,13 @@ const StudentView: React.FC<StudentViewProp> = ({
const [suggestion, setSuggestion] = useState('');
const [motivation, setMotivation] = useState('');
const [deletePopup, setDeletePopup] = useState(false);
const [editionActive, setEditionActive] = useState(true);
const [error, setError] = useState('');
const router = useRouter();
let controller = new AbortController();

fetchEditionState(setEditionActive, setError, router);

useEffect(() => {
setStudentBaseList(studentInput);
}, [studentInput]);
Expand Down Expand Up @@ -400,7 +408,12 @@ const StudentView: React.FC<StudentViewProp> = ({
</div>

{/* holds suggestion controls */}
<div className={`mr-8 ml-8 mb-6 flex flex-col xl:mb-0 xl:ml-0`}>
<div
className={
`mr-8 ml-8 mb-6 flex flex-col xl:mb-0 xl:ml-0 ` +
(editionActive ? 'visible' : 'hidden')
}
>
{/* regular coach status suggestion form */}
<form
className={`border-2 p-2`}
Expand Down
95 changes: 93 additions & 2 deletions frontend/lib/requestUtils.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { axiosAuthenticated } from './axios';
import { Skill, Url, User, UserRole } from './types';
import { Edition, Skill, Url, User, UserRole } from './types';
import Endpoints from './endpoints';
import axios, { AxiosError } from 'axios';
import axios, { AxiosError, AxiosResponse } from 'axios';
import { NextRouter } from 'next/dist/client/router';
import { useEffect } from 'react';

/**
* Function to parse axios request errors
Expand Down Expand Up @@ -162,3 +163,93 @@ export async function getUrlMap<Type>(
parseError(err, setError, router, signal);
});
}

/**
* Function that will try to run func and if it fails run it again, if it succeeds the result will be given to
* the function provided in doSomething.
*
* @param func - Function to get the result from
* @param doSomething - Function to use the result with
* @param signal - AbortSignal for the axios request
* @param setError - Callback to set error message
* @param router - Router object needed for error handling on 418 response
*/
async function retryOnce<T>(
func: () => Promise<T>,
doSomething: (arg: T) => void,
signal: AbortSignal,
setError: (error: string) => void,
router: NextRouter
) {
try {
const result = await func();
doSomething(result);
} catch (err) {
try {
const result = await func();
doSomething(result);
} catch (err) {
parseError(err, setError, router, signal);
}
}
}

/**
* Check if there is an active edition, if so then we can compare. If there is no active edition then we know for
* sure that the current edition is not active.
*
* @param setEditionActive - Function that sets the state
* @param signal - AbortSignal for the axios request
* @param setError - Callback to set error message
* @param router - Router object needed for error handling on 418 response
*/
async function loadEdition(
setEditionActive: (active: boolean) => void,
signal: AbortSignal,
setError: (error: string) => void,
router: NextRouter
) {
await retryOnce(
async () => {
return await axiosAuthenticated.get<Edition>(Endpoints.EDITIONACTIVE);
},
(response: AxiosResponse<Edition>) => {
if (response.data) {
const edition = router.query.editionName as string;
setEditionActive(edition == response.data.name);
return;
}
setEditionActive(false);
},
signal,
setError,
router
);
return;
}

/**
* Fetch the state of the current edition(active or inactive) and set it in the state using setEditionActive.
*
* @param setEditionActive - Function that sets the state
* @param setError - Callback to set error message
* @param router - Router object needed for error handling on 418 response
*/
export function fetchEditionState(
setEditionActive: (v: boolean) => void,
setError: (error: string) => void,
router: NextRouter
) {
useEffect(() => {
const controller = new AbortController();
const signal = controller.signal;
if (router.isReady) {
(async () => {
await loadEdition(setEditionActive, signal, setError, router);
})();
}
return () => {
controller.abort();
};
}, [router.isReady]);
}
12 changes: 10 additions & 2 deletions frontend/pages/[editionName]/communications.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ import { SpinnerCircular } from 'spinners-react';
import Error from '../../components/Error';
import useAxiosAuth from '../../hooks/useAxiosAuth';
import Endpoints from '../../lib/endpoints';
import { getUrlList, parseError } from '../../lib/requestUtils';
import {
fetchEditionState,
getUrlList,
parseError,
} from '../../lib/requestUtils';
import CommsCreationPopup from '../../components/communications/CommsCreationPopup';
import CsvDownloader from 'react-csv-downloader';
import PersistLogin from '../../components/PersistLogin';
Expand Down Expand Up @@ -46,11 +50,14 @@ const communications = () => {
page: 0,
hasMore: true,
});
const [editionActive, setEditionActive] = useState(true);

const axiosAuth = useAxiosAuth();
const [retry, setRetry] = useState(true);
let controller = new AbortController();

fetchEditionState(setEditionActive, setError, router);

/**
* Fetches students and their communications and updates the state of the application accordingly.
*
Expand Down Expand Up @@ -227,8 +234,9 @@ const communications = () => {
)}
<div>
<button
className="mx-2 my-1 rounded-sm bg-osoc-btn-primary px-2 py-1 text-black hover:brightness-95"
className="mx-2 my-1 rounded-sm bg-osoc-btn-primary px-2 py-1 text-black hover:brightness-95 disabled:cursor-not-allowed disabled:brightness-75"
onClick={() => setOpenPopup(true)}
disabled={!editionActive}
>
Add New
</button>
Expand Down
17 changes: 14 additions & 3 deletions frontend/pages/[editionName]/projects.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ import FlatList from 'flatlist-react';
import useUser from '../../hooks/useUser';
import { SpinnerCircular } from 'spinners-react';
import Error from '../../components/Error';
import { getUrlMap, parseError } from '../../lib/requestUtils';
import {
fetchEditionState,
getUrlMap,
parseError,
} from '../../lib/requestUtils';
import RouteProtection from '../../components/RouteProtection';
import { useRouter } from 'next/router';
import { NextRouter } from 'next/dist/client/router';
Expand Down Expand Up @@ -230,12 +234,15 @@ const Projects: NextPage = () => {
const [projectForm, setProjectForm] = useState(
JSON.parse(JSON.stringify({ ...defaultprojectForm }))
);
const [editionActive, setEditionActive] = useState(true);

const edition = router.query.editionName as string;

let controller = new AbortController();
useAxiosAuth();

fetchEditionState(setEditionActive, setError, router);

useEffect(() => {
state.page = 0;
if (router.isReady) {
Expand Down Expand Up @@ -541,8 +548,11 @@ const Projects: NextPage = () => {
<button
className={`${
user.role == UserRole.Admin ? 'visible' : 'hidden'
} justify-right ml-2 min-w-[160px] rounded-sm bg-check-orange px-2 py-1 text-sm font-medium text-black shadow-sm shadow-gray-300`}
onClick={() => setShowCreateProject(true)}
} justify-right ml-2 min-w-[160px] rounded-sm bg-check-orange px-2 py-1 text-sm font-medium text-black shadow-sm shadow-gray-300 disabled:cursor-not-allowed disabled:brightness-75`}
onClick={() => {
setShowCreateProject(true);
}}
disabled={!editionActive}
>
Create new project
</button>
Expand All @@ -566,6 +576,7 @@ const Projects: NextPage = () => {
projectInput={project}
conflictStudents={[] as string[]}
refreshProjects={refreshProjects}
editionActive={editionActive}
/>
)}
renderWhenEmpty={showBlank} // let user know if initial data is loading or there is no data to show
Expand Down
1 change: 1 addition & 0 deletions frontend/pages/editions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ const Editions: NextPage = () => {

const updateEdition = (_edition: string) => {
setEdition(_edition);
localStorage.setItem('edition', _edition);
router.push(`/${_edition}/projects`);
};

Expand Down

0 comments on commit 5e276e4

Please sign in to comment.