Skip to content
Closed
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
11 changes: 11 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import EventStatsPage from 'Pages/Events/EventStats';
import TicketUserList from './Pages/Ticket/TicketUserList';
import TicketDescPage from './Pages/Ticket/TicketDesc';
import EventScheduleCreate from 'Pages/Events/EventScheduleCreate';
import EventResults from 'Pages/Events/EventResults';

function App() {
return (
Expand Down Expand Up @@ -168,6 +169,16 @@ function EventsRoutes() {
</ProtectedRoute>
}
/>,
<Route
path="/events/results/:id"
element={
<ProtectedRoute
allowedRoles={[...allEventEditRoles, ...allEventViewRoles, ...specificEventViewRoles]}
>
<EventResults />
</ProtectedRoute>
}
/>,

<Route
path="/events/registrations/statistics"
Expand Down
7 changes: 7 additions & 0 deletions src/Components/Events/EventDesc/EventData/EventData.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,13 @@ export default function EventData({ event }: { event: IEvent }) {
<Typography>{event?.eventStatus}</Typography>
</Grid>

<Grid item xs={6}>
<Typography>Results Published</Typography>
</Grid>
<Grid item xs={6}>
<Typography>{event?.results && event.results.length > 0 ? 'YES' : 'NO'}</Typography>
</Grid>

<Grid item xs={6}>
<Typography>Number of Rounds</Typography>
</Grid>
Expand Down
12 changes: 9 additions & 3 deletions src/Components/Events/EventDesc/ToolBar/ToolBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@ import { Link as RouterLink } from 'react-router-dom';
import './ToolBar.css';
import { useNavigate } from 'react-router-dom';

export default function ToolBar({ eventId }: { eventId: number }) {
export default function ToolBar({
eventId,
resultsPublished,
}: {
eventId: number;
resultsPublished?: boolean;
}) {
const navigate = useNavigate();
return (
<Box className="event-desc-toolbar" component={Paper} elevation={2} borderRadius={0} zIndex={5}>
Expand Down Expand Up @@ -38,11 +44,11 @@ export default function ToolBar({ eventId }: { eventId: number }) {

<Button
variant="contained"
color="primary"
color={resultsPublished ? 'primary' : 'inherit'}
startIcon={<MilitaryTechIcon />}
className="toolbutton"
onClick={() => {
alert('Coming Soon!');
navigate(`/events/results/${eventId}`);
}}
>
Results
Expand Down
9 changes: 8 additions & 1 deletion src/Hooks/Event/create-update/eventValidation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,14 @@ import { InferType, ObjectSchema, boolean, date, mixed, number, object, string }
export const eventValidationSchema: ObjectSchema<
Omit<
IEvent,
'eventStatus' | 'category' | 'eventType' | 'eventHead1' | 'eventHead2' | 'icon' | 'id'
| 'eventStatus'
| 'category'
| 'eventType'
| 'eventHead1'
| 'eventHead2'
| 'icon'
| 'id'
| 'results'
> & { icon: File | undefined }
> = object().shape({
name: string()
Expand Down
13 changes: 13 additions & 0 deletions src/Hooks/Event/eventTypes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,24 @@ export interface IEvent extends IEventListItem {
registrationEndDate?: Date;
button: TEventButton;
registrationLink?: string;
results: IResult[];

// rounds: [];
// registration: null;
}

export interface IResult {
id: number;
eventId: number;
excelId: number;
teamId: number;
event?: IEvent;
position: number;
name: string;
teamName: string;
teamMembers: string;
}

export interface IEventHead {
id: number;
name: string;
Expand Down
16 changes: 15 additions & 1 deletion src/Hooks/Event/useEventDesc.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useContext, useState } from 'react';
import { ApiContext } from '../../Contexts/Api/ApiContext';
import { getErrMsg } from '../errorParser';
import { IEvent } from './eventTypes';
import { IEvent, IResult } from './eventTypes';

export function useEventDesc() {
const [event, setEvent] = useState<IEvent>();
Expand All @@ -19,12 +19,26 @@ export function useEventDesc() {
registrationEndDate: string;
}

interface IResultResponse {
isTeam: boolean;
results: IResult[];
}

const response = await axiosEventsPrivate.get<IEventResponse>(`/api/events/${eventId}`);

const resultsResponse = await axiosEventsPrivate.get<IResultResponse>(
`/api/Result/event/${eventId}`,
);

resultsResponse.data.results.sort((a: IResult, b: IResult) => {
return a.position - b.position;
});

const eventData: IEvent = {
...response.data,
datetime: new Date(response.data?.datetime),
registrationEndDate: new Date(response.data?.registrationEndDate),
results: resultsResponse.data.results,
};

setEvent(eventData);
Expand Down
6 changes: 3 additions & 3 deletions src/Hooks/Event/useScheduleList.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useContext, useState } from 'react';
import { useCallback, useContext, useState } from 'react';
import { ApiContext } from 'Contexts/Api/ApiContext';
import {
getErrMsg,
Expand Down Expand Up @@ -209,7 +209,7 @@ export function useScheduleList() {
}
};

function validateSchedule(): boolean {
const validateSchedule = useCallback((): boolean => {
try {
createEventScheduleValidationSchema.validateSync(newEvent, {
abortEarly: false,
Expand All @@ -227,7 +227,7 @@ export function useScheduleList() {
}
return false;
}
}
}, [newEvent]);

async function createSchedule(): Promise<TupdateFnReturn> {
try {
Expand Down
2 changes: 1 addition & 1 deletion src/Pages/Events/EventDesc.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export default function EventDescPage() {
</Box>
<br />

<ToolBar eventId={event!.id} />
<ToolBar eventId={event!.id} resultsPublished={event?.results && event.results.length > 0} />
<EventData event={event!} />
</>
);
Expand Down
181 changes: 181 additions & 0 deletions src/Pages/Events/EventResults.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
import { Box, Button, Divider, Grid, Paper, Typography } from '@mui/material';
import { useContext, useEffect } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import { useEventDesc } from '../../Hooks/Event/useEventDesc';
import UserContext from 'Contexts/User/UserContext';
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import {
allEventEditRoles,
allEventViewRoles,
specificEventViewRoles,
} from 'Hooks/Event/eventRoles';

export default function EventResults() {
const { event, fetchEvent, loading, error, setError } = useEventDesc();
const { userData } = useContext(UserContext);
const { id } = useParams<{ id: string }>();
const navigate = useNavigate();

useEffect(() => {
if (!Number.isInteger(Number(id))) {
setError('Invalid Event ID');
}
fetchEvent(Number(id));
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [id]);

useEffect(() => {
if (loading || !event) return;

if (userData.roles.some((role) => allEventEditRoles.includes(role))) {
} else if (userData.roles.some((role) => allEventViewRoles.includes(role))) {
} else if (userData.roles.some((role) => specificEventViewRoles.includes(role))) {
if (
event?.eventHead1?.email === userData.email ||
event?.eventHead2?.email === userData.email
) {
} else {
setError('You do not have permission to view this page');
}
} else {
setError('You do not have permission to view this page');
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [event, loading, userData]);

if (error) {
return <Typography variant="h5">{error}</Typography>;
}

if (loading || !event) {
return <Typography variant="h5">Loading...</Typography>;
}

return (
<Box
sx={{
display: 'flex',
height: '100%',
flexDirection: 'column',
alignItems: 'center',
width: '100%',
}}
>
<br />
<Box
sx={{
display: 'flex',
justifyContent: 'center',
width: '100%',
}}
>
<Typography variant="h5" noWrap>
Event Results: {event.name}
</Typography>
</Box>
<br />

<Box
sx={{
width: '90%',
marginBottom: '20px',
flexGrow: 1,
display: 'flex',
flexDirection: 'column',
}}
component={Paper}
elevation={2}
>
<Box
sx={{
width: '100%',
display: 'flex',
padding: '10px 30px',
justifyContent: 'space-between',
alignItems: 'center',
}}
component={Paper}
elevation={2}
borderRadius={0}
zIndex={5}
>
<Button
variant="contained"
color="primary"
startIcon={<ArrowBackIcon />}
onClick={() => {
navigate(-1);
}}
>
Back
</Button>
<Box sx={{ flexGrow: 1 }} />
</Box>

<Box sx={{ padding: 3 }}>
<Grid container spacing={2}>
{event.results && event.results.length > 0 ? (
<>
<Grid item xs={12}>
<Typography variant="h5">Results</Typography>
</Grid>
<Grid item xs={12}>
<Divider />
</Grid>

{/* 1st Place */}
<Grid item xs={3}>
<Typography>1st </Typography>
</Grid>
<Grid item xs={3}>
<Typography>
{event.results.length >= 1 ? event.results[0].teamName : ''}
</Typography>
</Grid>
<Grid item xs={6}>
<Typography>
{event.results.length >= 1 ? event.results[0].teamMembers : ''}
</Typography>
</Grid>

{/* 2nd Place */}
<Grid item xs={3}>
<Typography>2nd </Typography>
</Grid>
<Grid item xs={3}>
<Typography>
{event.results.length >= 2 ? event.results[1].teamName : ''}
</Typography>
</Grid>
<Grid item xs={6}>
<Typography>
{event.results.length >= 2 ? event.results[1].teamMembers : ''}
</Typography>
</Grid>

{/* 3rd Place */}
<Grid item xs={3}>
<Typography>3rd </Typography>
</Grid>
<Grid item xs={3}>
<Typography>
{event.results.length >= 3 ? event.results[2].teamName : ''}
</Typography>
</Grid>
<Grid item xs={6}>
<Typography>
{event.results.length >= 3 ? event.results[2].teamMembers : ''}
</Typography>
</Grid>
</>
) : (
<Grid item xs={12}>
<Typography align="center">No results declared yet.</Typography>
</Grid>
)}
</Grid>
</Box>
</Box>
</Box>
);
}