Skip to content

Commit

Permalink
Merge pull request #98 from OxfordRSE/test_profile
Browse files Browse the repository at this point in the history
Speedup render of eventProblems table
  • Loading branch information
martinjrobins authored Nov 1, 2023
2 parents fc8d638 + 75ab50b commit 676cefb
Show file tree
Hide file tree
Showing 5 changed files with 428 additions and 21 deletions.
34 changes: 21 additions & 13 deletions components/EventProblems.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Course, Material, Section, Theme, eventItemSplit } from 'lib/material'
import { EventFull, Event, Problem } from 'lib/types'
import useSWR, { Fetcher } from 'swr'
import Title from 'components/ui/Title'
import { Avatar, Button, Card, Table, Timeline, Tooltip } from 'flowbite-react'
import { Avatar, Button, Card, Table, Timeline } from 'flowbite-react'
import { ListGroup } from 'flowbite-react';
import { basePath } from 'lib/basePath'
import { MdClose } from 'react-icons/md'
Expand All @@ -16,44 +16,52 @@ import { EventItem } from '@prisma/client';
import useUsers from 'lib/hooks/useUsers';
import { useProblems } from 'lib/hooks/useProblems';
import useUsersOnEvent from 'lib/hooks/useUsersOnEvent';
import { filter } from 'cypress/types/bluebird';
import Tooltip from '@mui/material/Tooltip';

type Props = {
event: EventFull,
material: Material,
}




// a table of eventItems vs users showing which users have completed which problems
const EventProblems: React.FC<Props> = ({ material, event }) => {
const { users, error: usersError } = useUsersOnEvent(event.id);
const { problems, error: problemsError } = useProblems(event.id);

if (usersError || problemsError) return <div>failed to load</div>
if (!users || !problems) return <div>loading...</div>
const students = users.filter((user) => user.status === 'STUDENT')
const students = users.filter((user) => user.status === 'STUDENT' && user.eventId === event.id)

const userProblems: { [key: string]: Problem[] } = {};
users.forEach((user) => {
const filteredProblems = problems.filter((problem) => problem.userEmail === user.userEmail);
if (filteredProblems) {userProblems[user.userEmail] = filteredProblems;}
});

return (
<Table className='border dark:border-gray-700'>
<Table.Head>
<Table.HeadCell>
Problem
</Table.HeadCell>
{ students?.map((user) => (
<Table.HeadCell key={user.userEmail} align="center">
<Tooltip className={'normal-case'} content={`${user?.user?.name} <${user?.userEmail}>`} placement="top">
<Table.HeadCell key={user.userEmail} align="center" className="p-0">
<Tooltip className={'normal-case'} title={`${user?.user?.name} <${user?.userEmail}>`} placement="top">
<Avatar
img={user?.user?.image || undefined}
rounded={true}
size="sm"
size="xs"
/>
</Tooltip>
</Table.HeadCell>
))}
</Table.Head>
<Table.Body className="divide-y">
{ event.EventGroup.map((eventGroup) => (
{ event.EventGroup.filter(
(eventGroup) => eventGroup.EventItem.length > 0)
.map((eventGroup) => (
<React.Fragment key={eventGroup.id}>
<Table.Row className="" key={eventGroup.id}>
<Table.Cell className="">
Expand All @@ -67,21 +75,21 @@ const EventProblems: React.FC<Props> = ({ material, event }) => {
{ section && section.problems.map((problem) => (
<React.Fragment key={problem}>
<Table.Row className="bg-white dark:border-gray-700 dark:bg-gray-800" key={`${eventGroup.id}-${eventGroup.id}-${problem}`}>
<Table.Cell className="whitespace-nowrap font-medium text-gray-900 dark:text-white" key={`title-${problem}${eventItem.section}`}>
<Table.Cell className="whitespace-nowrap font-medium text-gray-900 dark:text-white p-1 m-0" key={`title-${problem}-${eventItem.section}`}>
{url ? (
<a href={`${url}#${problem}`}>{problem}</a>
) : (
<span>{problem}</span>
)}
</Table.Cell>
{ students?.map((user, i) => {
const problemStruct = problems.find((p: Problem) => p.userEmail === user.userEmail && p.tag === problem)
const problemStruct = userProblems[user.userEmail].find((p) => p.tag === problem)
const problemStr = `difficulty: ${problemStruct?.difficulty} notes: ${problemStruct?.notes}`
return (
<Table.Cell key={`${user.userEmail}${problem}${eventItem.section}`} align='center' className="whitespace-nowrap font-medium text-gray-900 dark:text-white">
<Table.Cell key={`${user.userEmail}-${problem}-${eventItem.section}-${problem}`} align='center' className="whitespace-nowrap font-medium text-gray-900 dark:text-white p-0">
{(problemStruct && problemStruct.complete) ?
<Tooltip content={problemStr} placement="top"></Tooltip> :
'❌'
<Tooltip title={problemStr} placement="top"><span></span></Tooltip> :
<span></span>
}
</Table.Cell>
)
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
"seed": "ts-node --compiler-options {\"module\":\"CommonJS\"} prisma/seed.ts"
},
"dependencies": {
"@emotion/react": "^11.7.1",
"@emotion/styled": "^11.7.1",
"@mui/material": "^5.2.5",
"@next-auth/prisma-adapter": "^1.0.5",
"@prisma/client": "^4.11.0",
"@tailwindcss/aspect-ratio": "^0.4.2",
Expand Down
15 changes: 13 additions & 2 deletions pages/api/event/[eventId]/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import prisma from 'lib/prisma'
import type { NextApiRequest, NextApiResponse } from 'next'
import _, { sortBy } from "cypress/types/lodash"
import { Prisma } from "@prisma/client"
import useProfile from "lib/hooks/useProfile"

export type UsersWithUserOnEvents = Prisma.UserOnEventGetPayload<{
include: { user: true }
Expand All @@ -23,6 +24,7 @@ const EventUsers = async (
const { method } = req;
const session = await getServerSession(req, res, authOptions)
const user = session?.user;
const userEmail = session?.user?.email
const eventId = parseInt(req.query.eventId as string);

if (!session) {
Expand All @@ -42,12 +44,21 @@ const EventUsers = async (
return res.status(404).json({ error: 'Event not Found' })
}

if (!userEmail || userEmail === undefined) {
return res.status(401).send({ error: "Not logged in" });
}

const currentUser = await prisma.user.findUnique({
where: { email: userEmail },
});

const isInstructor = event?.UserOnEvent.some((userOnEvent) => userOnEvent?.user?.name === user?.name && userOnEvent.status === 'INSTRUCTOR')
const isAdmin = currentUser?.admin === true;

let users: UsersWithUserOnEvents[] = []
switch (method) {
case 'GET':
if (isInstructor) {
if (isInstructor || isAdmin) {
const onEvent = event?.UserOnEvent
const emails = onEvent.map((userOnEvent) => userOnEvent?.userEmail || "")
users = await prisma.userOnEvent.findMany({
Expand All @@ -59,7 +70,7 @@ const EventUsers = async (
res.status(200).json({ users })
break;
case 'PUT':
if (!isInstructor) {
if (!isInstructor && !isAdmin) {
return res.status(403).json({ error: 'Forbidden' });
}
users = req.body.users;
Expand Down
1 change: 0 additions & 1 deletion pages/event/[eventId].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ const Event: NextPage<EventProps> = ({ material, event, pageInfo}) => {
{ label: 'reject', value: 'REJECTED' },
]


const eventView = (
<>
<Title text={event.name} />
Expand Down
Loading

0 comments on commit 676cefb

Please sign in to comment.