Skip to content

Commit d55c55a

Browse files
authored
Merge pull request #4 from ky28059/main
Pull more build error fixes, dep updates
2 parents df1d5f0 + 72ac553 commit d55c55a

File tree

8 files changed

+225
-79
lines changed

8 files changed

+225
-79
lines changed

app/login-handler/route.ts

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { NextRequest, NextResponse } from 'next/server';
2+
import { login } from '@/util/auth';
3+
4+
5+
export async function GET(req: NextRequest) {
6+
const params = req.nextUrl.searchParams;
7+
8+
const token = params.get('token');
9+
if (!token)
10+
return NextResponse.redirect(new URL('/login', req.url));
11+
12+
const res = await login(token);
13+
if ('error' in res)
14+
return NextResponse.redirect(new URL(`/login?error=${res.error}`, req.url));
15+
16+
return NextResponse.redirect(new URL('/profile', req.url));
17+
}

app/login/LoginContent.tsx

+7-13
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use client'
22

3-
import { useLayoutEffect, useState } from 'react';
4-
import { useRouter, useSearchParams } from 'next/navigation';
3+
import { useState } from 'react';
4+
import { useRouter } from 'next/navigation';
55
import Link from 'next/link';
66
import { login } from '@/util/auth';
77

@@ -12,20 +12,14 @@ import IconInput from '@/components/IconInput';
1212
import { FaAddressCard } from 'react-icons/fa6';
1313

1414

15-
export default function LoginContent() {
15+
type LoginContentProps = {
16+
error?: string
17+
}
18+
export default function LoginContent(props: LoginContentProps) {
1619
const [teamToken, setTeamToken] = useState('');
17-
const [error, setError] = useState('');
20+
const [error, setError] = useState(props.error ?? '');
1821

1922
const router = useRouter();
20-
const params = useSearchParams();
21-
22-
// Automatically sign in if the `token` URL search parameter is set.
23-
useLayoutEffect(() => {
24-
const token = params.get('token');
25-
if (!token) return;
26-
27-
void loginCallback(token);
28-
}, [params.get('token')]);
2923

3024
async function loginCallback(teamToken: string) {
3125
const res = await login(teamToken);

app/login/page.tsx

+11-2
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,28 @@
11
import type { Metadata } from 'next';
2+
import { redirect } from 'next/navigation';
3+
4+
// Components
25
import LoginContent from '@/app/login/LoginContent';
36

47

58
export const metadata: Metadata = {
69
title: 'Log in'
710
}
811

9-
export default function Login() {
12+
export default async function Login({ searchParams }: { searchParams: Promise<{ token?: string, error?: string }> }) {
13+
const token = (await searchParams).token;
14+
const error = (await searchParams).error;
15+
16+
// Automatically sign in if the `token` search parameter is set.
17+
if (token) return redirect(`/login-handler?token=${token}`)
18+
1019
return (
1120
<div className="container pt-32 pb-24">
1221
<h1 className="text-2xl font-bold mb-8 text-center">
1322
Log in to b01lers internal CTF
1423
</h1>
1524

16-
<LoginContent />
25+
<LoginContent error={error} />
1726
</div>
1827
)
1928
}

app/profile/[id]/page.tsx

+4-4
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,17 @@ import Profile from '@/app/profile/Profile';
88
import { getProfile } from '@/util/profile';
99

1010

11-
export async function generateMetadata({ params }: { params: { id: string } }): Promise<Metadata> {
12-
const data = await getProfile(params.id);
11+
export async function generateMetadata({ params }: { params: Promise<{ id: string }> }): Promise<Metadata> {
12+
const data = await getProfile((await params).id);
1313
if (data.kind === 'badUnknownUser') return notFound();
1414

1515
return {
1616
title: data.data.name
1717
}
1818
}
1919

20-
export default async function ProfilePage({ params }: { params: { id: string } }) {
21-
const data = await getProfile(params.id);
20+
export default async function ProfilePage({ params }: { params: Promise<{ id: string }> }) {
21+
const data = await getProfile((await params).id);
2222
if (data.kind === 'badUnknownUser') return notFound();
2323

2424
return (

app/verify/page.tsx

+4-3
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@ export const metadata: Metadata = {
1313
title: 'Verify'
1414
}
1515

16-
export default async function Verify({ searchParams }: { searchParams: { token: string } }) {
17-
if (!searchParams.token)
16+
export default async function Verify({ searchParams }: { searchParams: Promise<{ token: string }> }) {
17+
const token = (await searchParams).token;
18+
if (!token)
1819
return redirect('/register');
1920

20-
const res = await verify(searchParams.token);
21+
const res = await verify(token);
2122
if (res.kind === 'goodEmailSet')
2223
return redirect('/profile');
2324
if (res.kind !== 'goodRegister' && res.kind !== 'goodVerify')

components/CenteredModal.tsx

+22-32
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,34 @@
1-
import { Fragment, ReactNode } from 'react';
2-
import { Dialog, Transition } from '@headlessui/react';
1+
import type { ReactNode } from 'react';
2+
import { Dialog, DialogBackdrop, DialogPanel } from '@headlessui/react';
33

44

55
// A reusable component to wrap a transition and dialog overlay around a screen-centered div.
66
type CenteredModalProps = {
7-
isOpen: boolean, setIsOpen: (isOpen: boolean) => void,
8-
className: string, children: ReactNode
7+
isOpen: boolean,
8+
setIsOpen: (isOpen: boolean) => void,
9+
className: string,
10+
children: ReactNode
911
}
1012
export default function CenteredModal(props: CenteredModalProps) {
1113
const { isOpen, setIsOpen, className, children } = props;
1214

1315
return (
14-
<Transition show={isOpen} as={Fragment}>
15-
<Dialog onClose={() => setIsOpen(false)} className="fixed z-40 inset-0 flex items-center justify-center">
16-
<Transition.Child
17-
as={Fragment}
18-
enter="ease-out duration-300"
19-
enterFrom="opacity-0"
20-
enterTo="opacity-100"
21-
leave="ease-in duration-200"
22-
leaveFrom="opacity-100"
23-
leaveTo="opacity-0"
24-
>
25-
<div className="fixed inset-0 bg-black/40" />
26-
</Transition.Child>
16+
<Dialog
17+
className="fixed z-40 inset-0 flex items-center justify-center"
18+
open={isOpen}
19+
onClose={() => setIsOpen(false)}
20+
>
21+
<DialogBackdrop
22+
transition
23+
className="fixed inset-0 bg-black/40 transition duration-300 data-[closed]:duration-200 ease-out data-[closed]:ease-in data-[closed]:opacity-0"
24+
/>
2725

28-
<Transition.Child
29-
as={Fragment}
30-
enter="ease-out duration-300"
31-
enterFrom="opacity-0 scale-95"
32-
enterTo="opacity-100 scale-100"
33-
leave="ease-in duration-200"
34-
leaveFrom="opacity-100 scale-100"
35-
leaveTo="opacity-0 scale-95"
36-
>
37-
<Dialog.Panel className={className}>
38-
{children}
39-
</Dialog.Panel>
40-
</Transition.Child>
41-
</Dialog>
42-
</Transition>
26+
<DialogPanel
27+
transition
28+
className={className + ' transition duration-300 data-[closed]:duration-200 ease-out data-[closed]:ease-in data-[closed]:scale-95 data-[closed]:opacity-0'}
29+
>
30+
{children}
31+
</DialogPanel>
32+
</Dialog>
4333
)
4434
}

0 commit comments

Comments
 (0)