Skip to content

Commit d845751

Browse files
authored
Update reported team display
displays reported teams at the top of view teams page; populates team based on report count; updated async promises to next.js 15+
2 parents 1e4d072 + 91a89fd commit d845751

File tree

12 files changed

+756
-217
lines changed

12 files changed

+756
-217
lines changed

app/(api)/_actions/invite/getInviteData.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ export async function getInviteData() {
1212
if (noUsers) {
1313
return null;
1414
} else {
15-
const data = cookies().get('data');
15+
const cookieStore = await cookies();
16+
const data = cookieStore.get('data');
1617
if (!data) return null;
1718

1819
const dataJson = atob(data.value);

app/(api)/_actions/invite/processInvite.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ export async function processInvite(slug: string) {
1010
const data = slugComponents[0];
1111
const sig = slugComponents[1];
1212

13-
cookies().set('data', data, { httpOnly: true });
14-
cookies().set('sig', sig, { httpOnly: true });
13+
const cookieStore = await cookies();
14+
cookieStore.set('data', data, { httpOnly: true });
15+
cookieStore.set('sig', sig, { httpOnly: true });
1516

1617
return true;
1718
}

app/(api)/_utils/authentication/authenticated.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import { auth } from '@/auth';
44
import { HttpError, NotAuthenticatedError } from '@utils/response/Errors';
55

66
export default function authenticated(
7-
handler: (request: NextRequest, params: any) => Promise<NextResponse>
7+
handler: (request: NextRequest, params?: any) => Promise<NextResponse>
88
) {
9-
return async (request: NextRequest, params: object) => {
9+
return async (request: NextRequest, params?: any) => {
1010
try {
1111
const session = await auth();
1212
if (!session) {

app/(api)/api/auth/logout/route.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
'use server';
22

3-
import { NextResponse } from 'next/server';
3+
import { NextRequest, NextResponse } from 'next/server';
44

55
import Logout from '@datalib/auth/logout';
66
import authenticated from '@utils/authentication/authenticated';
77

8-
async function post() {
8+
async function post(_: NextRequest) {
99
const res = await Logout();
1010
return NextResponse.json({ ...res }, { status: res.ok ? 200 : 401 });
1111
}

app/(pages)/(magic-link)/invite/[slug]/page.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,18 @@ import { useRouter } from 'next/navigation';
55
import { processInvite } from '@actions/invite/processInvite';
66
import Loader from '@pages/_components/Loader/Loader';
77

8-
export default function Page({ params }: { params: { slug: string } }) {
8+
export default function Page({
9+
params,
10+
}: {
11+
params: Promise<{ slug: string }>;
12+
}) {
913
const router = useRouter();
1014
const [valid, setValid] = useState(true);
1115

1216
useEffect(() => {
1317
const handleInvite = async () => {
14-
if (await processInvite(params.slug)) {
18+
const resolvedParams = await params;
19+
if (await processInvite(resolvedParams.slug)) {
1520
setValid(true);
1621
router.push('/register');
1722
} else {

app/(pages)/(magic-link)/reset/[slug]/page.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,18 @@ import { useRouter } from 'next/navigation';
55
import { processInvite } from '@actions/invite/processInvite';
66
import Loader from '@pages/_components/Loader/Loader';
77

8-
export default function Page({ params }: { params: { slug: string } }) {
8+
export default function Page({
9+
params,
10+
}: {
11+
params: Promise<{ slug: string }>;
12+
}) {
913
const router = useRouter();
1014
const [valid, setValid] = useState(true);
1115

1216
useEffect(() => {
1317
const handleReset = async () => {
14-
if (await processInvite(params.slug)) {
18+
const resolvedParams = await params;
19+
if (await processInvite(resolvedParams.slug)) {
1520
setValid(true);
1621
router.push('/reset-password');
1722
} else {

app/(pages)/_components/InviteOnlyRoute/InviteOnlyRoute.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ export default async function InviteOnlyRoute({
88
}: {
99
children: React.ReactNode;
1010
}) {
11-
const data = cookies().get('data');
12-
const sig = cookies().get('sig');
11+
const cookieStore = await cookies();
12+
const data = cookieStore.get('data');
13+
const sig = cookieStore.get('sig');
1314

1415
const users = await getManyUsers();
1516
const noUsers = users.body.length === 0;

app/(pages)/admin/teams/page.module.scss

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,29 @@ $data-gap: 24px;
8282
.action_header {
8383
font-size: 1.75rem;
8484
}
85+
86+
.reported_teams_container {
87+
display: flex;
88+
gap: 8px;
89+
margin-top: 10px;
90+
margin-bottom: 10px;
91+
}
92+
93+
.reports_container {
94+
display: grid;
95+
grid-template-columns: 1fr 1fr 1fr 1fr;
96+
gap: 4px;
97+
98+
@include desktop-m {
99+
grid-template-columns: 1fr 1fr;
100+
}
101+
}
102+
103+
.report_container {
104+
font-size: 0.9rem;
105+
color: black;
106+
padding: 6px 12px;
107+
border-radius: 8px;
108+
background: var(--text-gray-light);
109+
box-shadow: 0px 4px 8px 4px rgba(195, 194, 194, 0.08);
110+
}

app/(pages)/admin/teams/page.tsx

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import { useState } from 'react';
44
import { useTeams } from '@pages/_hooks/useTeams';
55
import { GoSearch } from 'react-icons/go';
6+
import { IoAdd } from 'react-icons/io5';
7+
import { RxCross1 } from 'react-icons/rx';
68
import TeamCard from '../_components/Teams/TeamCard';
79
import Team from '@typeDefs/team';
810
import User from '@typeDefs/user';
@@ -20,6 +22,7 @@ export default function Teams() {
2022
const { loading, teams, getTeams } = useTeams();
2123
const { data, setData } = useFormContext();
2224
const isEditing = Boolean(data._id);
25+
const [reportedTeamsDisplay, setReportedTeamsDisplay] = useState(false);
2326

2427
if (loading) {
2528
return 'loading...';
@@ -29,6 +32,10 @@ export default function Teams() {
2932
return teams.error;
3033
}
3134

35+
function toggleReportedTeamsDisplay() {
36+
setReportedTeamsDisplay(!reportedTeamsDisplay);
37+
}
38+
3239
const teamData: TeamWithJudges[] = teams.body
3340
.filter((team: TeamWithJudges) =>
3441
JSON.stringify(team).toLowerCase().includes(search.toLowerCase())
@@ -44,6 +51,8 @@ export default function Teams() {
4451
backgroundColor: '#9EE7E5',
4552
}));
4653

54+
const reportedTeams = teamData.filter((team) => team.reports?.length > 0);
55+
4756
return (
4857
<div className={styles.container}>
4958
<h1 className={styles.page_title}>Team Manager</h1>
@@ -65,15 +74,71 @@ export default function Teams() {
6574
/>
6675
<GoSearch className={styles.search_icon} />
6776
</div>
77+
<div className={styles.reported_teams_container}>
78+
<h2 className={styles.action_header}> Reported Teams</h2>
79+
<button
80+
onClick={toggleReportedTeamsDisplay}
81+
style={{
82+
fontSize: '1.25rem',
83+
display: 'flex',
84+
justifyContent: 'center',
85+
alignItems: 'center',
86+
width: '40px',
87+
height: '40px',
88+
backgroundColor: reportedTeamsDisplay
89+
? 'var(--text-error)'
90+
: 'var(--text-gray-light)',
91+
color: reportedTeamsDisplay ? 'white' : 'black',
92+
borderRadius: '6px',
93+
cursor: 'pointer',
94+
border: 'none',
95+
}}
96+
>
97+
{reportedTeamsDisplay ? <RxCross1 /> : <IoAdd />}
98+
</button>
99+
</div>
100+
<div className={styles.reports_container}>
101+
{reportedTeamsDisplay &&
102+
reportedTeams
103+
.sort((a, b) => (b.reports?.length || 0) - (a.reports?.length || 0))
104+
.map((team) => (
105+
<div className={styles.report_container} key={team._id}>
106+
<a href={`#${team._id}`}>
107+
<strong style={{ color: 'var(--text-error)' }}>
108+
[{team.reports?.length}]
109+
</strong>{' '}
110+
Table {team.tableNumber}: {team.name} (Team {team.teamNumber})
111+
</a>
112+
</div>
113+
))}
114+
</div>
68115
<div className={styles.data_portion}>
69116
<div className={styles.teams_list}>
70-
{teamData.map((team: TeamWithJudges) => (
71-
<div className={styles.team_card_wrapper} key={team._id}>
72-
<TeamCard team={team} onEditClick={() => setData(team)} />
73-
</div>
74-
))}
117+
{teamData
118+
.sort((a, b) => (b.reports?.length || 0) - (a.reports?.length || 0))
119+
.map((team: TeamWithJudges) => (
120+
<div
121+
id={team._id}
122+
className={styles.team_card_wrapper}
123+
key={team._id}
124+
>
125+
<TeamCard team={team} onEditClick={() => setData(team)} />
126+
</div>
127+
))}
128+
{teamData
129+
.sort((a, b) => (b.reports?.length || 0) - (a.reports?.length || 0))
130+
.map((team: TeamWithJudges) => (
131+
<div
132+
id={team._id}
133+
className={styles.team_card_wrapper}
134+
key={team._id}
135+
>
136+
<TeamCard team={team} onEditClick={() => setData(team)} />
137+
</div>
138+
))}
75139
</div>
76140
<div className={styles.bar_chart_container}>
141+
<h2 className={styles.action_header}>Judge Count</h2>
77142
<BarChart
78143
data={chartData}
79144
lines={[{ style: 'dashed 1px red', value: 3 }]}

app/(pages)/judges/(app)/score/[team-id]/page.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client';
22

3-
import { useState } from 'react';
3+
import { useState, useEffect } from 'react';
44
import styles from './page.module.scss';
55
import ScoringForm from '@components/ScoringForm/ScoringForm';
66
import Loader from '@components/Loader/Loader';
@@ -13,15 +13,19 @@ import { useTeam } from '@hooks/useTeam';
1313
import leftArrow from '@public/judges/scoring/left-arrow.svg';
1414

1515
interface ScoringFormProps {
16-
params: {
16+
params: Promise<{
1717
'team-id': string;
18-
};
18+
}>;
1919
}
2020

2121
export default function ScoreTeam({ params }: ScoringFormProps) {
2222
const [showInfo, setShowInfo] = useState(false);
23-
const { submission, loading: subLoading } = useSubmission(params['team-id']);
24-
const { team, loading: teamLoading } = useTeam(params['team-id']);
23+
const [teamId, setTeamId] = useState<string>('');
24+
useEffect(() => {
25+
params.then((p) => setTeamId(p['team-id']));
26+
}, [params]);
27+
const { submission, loading: subLoading } = useSubmission(teamId);
28+
const { team, loading: teamLoading } = useTeam(teamId);
2529
const loading = subLoading || teamLoading;
2630

2731
if (loading) {

0 commit comments

Comments
 (0)