Skip to content

Commit fb96bf7

Browse files
committed
Restructured hackers and judges to allow for better clarity and auth layout
1 parent b7639b4 commit fb96bf7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+141
-112
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { SessionProvider } from 'next-auth/react';
2+
3+
import ProtectedDisplay from '@components/ProtectedDisplay/ProtectedDisplay';
4+
5+
export default function Layout({ children }: { children: React.ReactNode }) {
6+
return (
7+
<SessionProvider>
8+
<ProtectedDisplay allowedRoles="hacker admin">
9+
{children}
10+
</ProtectedDisplay>
11+
</SessionProvider>
12+
);
13+
}

app/(pages)/(index)/page.tsx renamed to app/(pages)/(hackers)/(index)/page.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,13 @@ import { useState, FormEvent } from 'react';
44
import { useRouter } from 'next/navigation';
55

66
import HackerHub from './_components/HackerHub/HackerHub';
7-
import ProtectedDisplay from '@components/ProtectedDisplay/ProtectedDisplay';
87
import LogoutAction from '@actions/auth/logout';
98

109
export default function Page() {
1110
const router = useRouter();
1211
const [loading, setLoading] = useState(false);
1312

14-
const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
13+
const handleLogout = async (e: FormEvent<HTMLFormElement>) => {
1514
e.preventDefault();
1615

1716
setLoading(true);
@@ -24,13 +23,13 @@ export default function Page() {
2423
};
2524

2625
return (
27-
<ProtectedDisplay allowedRoles="hacker admin">
26+
<>
2827
<HackerHub />
29-
<form onSubmit={handleSubmit}>
28+
<form onSubmit={handleLogout}>
3029
<button type="submit" disabled={loading}>
3130
Sign Out
3231
</button>
3332
</form>
34-
</ProtectedDisplay>
33+
</>
3534
);
3635
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
'use client';
2+
3+
import { useState, useEffect, FormEvent, ChangeEvent } from 'react';
4+
import { useRouter } from 'next/navigation';
5+
6+
import LoginAction from '@actions/auth/login';
7+
import styles from './LoginForm.module.scss';
8+
9+
export default function LoginForm() {
10+
const router = useRouter();
11+
12+
const [email, setEmail] = useState('');
13+
const [password, setPassword] = useState('');
14+
const [valid, setValid] = useState(false);
15+
const [error, setError] = useState('');
16+
const [loading, setLoading] = useState(false);
17+
18+
const handleLogin = async (e: FormEvent<HTMLFormElement>) => {
19+
e.preventDefault();
20+
21+
setLoading(true);
22+
setError('');
23+
const formData = new FormData(e.currentTarget);
24+
const response = await LoginAction(
25+
formData.get('email'),
26+
formData.get('password')
27+
);
28+
setLoading(false);
29+
30+
if (response.ok) {
31+
router.push('/');
32+
} else {
33+
setError('Invalid email or password.');
34+
}
35+
};
36+
37+
const validateForm = (email: string, password: string) => {
38+
const isEmailValid = /\S+@\S+\.\S+/.test(email);
39+
const isPasswordValid = password.length >= 6;
40+
setValid(isEmailValid && isPasswordValid);
41+
};
42+
43+
useEffect(() => {
44+
validateForm(email, password);
45+
}, [email, password]);
46+
47+
return (
48+
<form onSubmit={handleLogin} className={styles.container}>
49+
<label htmlFor="email">Email</label>
50+
<input
51+
name="email"
52+
type="email"
53+
value={email}
54+
onInput={(e: ChangeEvent<HTMLInputElement>) => setEmail(e.target.value)}
55+
/>
56+
<label htmlFor="password">Password</label>
57+
<input
58+
name="password"
59+
type="password"
60+
value={password}
61+
onInput={(e: ChangeEvent<HTMLInputElement>) =>
62+
setPassword(e.target.value)
63+
}
64+
/>
65+
<p className={styles.error_msg}>{error}</p>
66+
<button type="submit" disabled={loading || !valid}>
67+
Log in →
68+
</button>
69+
</form>
70+
);
71+
}

app/(pages)/(index)/layout.tsx

Lines changed: 0 additions & 5 deletions
This file was deleted.

app/(pages)/(index)/login/_components/LoginForm.tsx

Lines changed: 0 additions & 45 deletions
This file was deleted.

app/(pages)/judging-app/layout.tsx renamed to app/(pages)/judges/(index)/layout.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { Metadata } from 'next';
22
import { SessionProvider } from 'next-auth/react';
33

4+
import ProtectedDisplay from '@components/ProtectedDisplay/ProtectedDisplay';
5+
46
type Props = {
57
children: React.ReactNode;
68
};
@@ -10,5 +12,9 @@ export const metadata: Metadata = {
1012
};
1113

1214
export default function JudgesLayout({ children }: Props) {
13-
return <SessionProvider>{children}</SessionProvider>;
15+
return (
16+
<SessionProvider>
17+
<ProtectedDisplay allowedRoles="admin judge">{children}</ProtectedDisplay>
18+
</SessionProvider>
19+
);
1420
}

app/(pages)/judges/(index)/page.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
'use client';
2+
import JudgingHub from './_components/JudgingHub/JudgingHub';
3+
4+
export default function Judges() {
5+
return <JudgingHub />;
6+
}

app/(pages)/judging-app/scoring/layout.tsx renamed to app/(pages)/judges/(index)/scoring/layout.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ type Props = {
88

99
export default function ScoringLayout({ children }: Props) {
1010
return (
11-
<ProtectedDisplay allowedRoles="admin judge" failRedirectPath="/login">
12-
{children}
13-
</ProtectedDisplay>
11+
<ProtectedDisplay allowedRoles="admin judge">{children}</ProtectedDisplay>
1412
);
1513
}

app/(pages)/judging-app/_components/LoginPage/LoginForm.module.scss renamed to app/(pages)/judges/login/_components/LoginForm.module.scss

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
border: none;
5252
border-radius: var(--b-radius);
5353
background-color: var(--background-secondary);
54-
cursor: not-allowed;
54+
cursor: pointer;
5555
width: 100%;
5656

5757
}
@@ -63,11 +63,11 @@
6363
flex-direction: column;
6464
}
6565

66-
.valid {
66+
.not_valid {
6767
background-color: var(--background-secondary-light);
6868
opacity: 0.7;
6969
color: var(--text-light);
70-
cursor: pointer;
70+
cursor: not-allowed;
7171
}
7272

7373
.froggie_container {

app/(pages)/judging-app/_components/LoginPage/LoginForm.tsx renamed to app/(pages)/judges/login/_components/LoginForm.tsx

Lines changed: 30 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { useEffect, useState, ChangeEvent } from 'react';
2-
import { useFormState } from 'react-dom';
1+
import { useEffect, useState, FormEvent, ChangeEvent } from 'react';
32
import { useRouter } from 'next/navigation';
43
import Image from 'next/image';
54
// import Link from 'next/link';
@@ -12,58 +11,51 @@ export default function LoginForm() {
1211

1312
const [email, setEmail] = useState('');
1413
const [password, setPassword] = useState('');
15-
const [isValid, setIsValid] = useState(false);
14+
const [valid, setValid] = useState(false);
1615
const [error, setError] = useState('');
16+
const [loading, setLoading] = useState(false);
1717

18-
const [loginState, Login] = useFormState(LoginAction, {
19-
ok: false,
20-
body: null,
21-
error: null,
22-
});
18+
const handleLogin = async (e: FormEvent<HTMLFormElement>) => {
19+
e.preventDefault();
2320

24-
const handleEmailChange = (event: ChangeEvent<HTMLInputElement>) => {
25-
setEmail(event.target.value);
26-
};
21+
setLoading(true);
22+
setError('');
23+
const formData = new FormData(e.currentTarget);
24+
const response = await LoginAction(
25+
formData.get('email'),
26+
formData.get('password')
27+
);
28+
setLoading(false);
2729

28-
const handlePasswordChange = (event: ChangeEvent<HTMLInputElement>) => {
29-
setPassword(event.target.value);
30+
if (response.ok) {
31+
router.push('/judges');
32+
} else {
33+
setError('Invalid email or password.');
34+
}
3035
};
3136

3237
const validateForm = (email: string, password: string) => {
33-
// Simple email validation
3438
const isEmailValid = /\S+@\S+\.\S+/.test(email);
35-
// Password validation (example: minimum length of 6 characters)
3639
const isPasswordValid = password.length >= 6;
37-
38-
// Set isValid state based on email and password validity
39-
setIsValid(isEmailValid && isPasswordValid);
40+
setValid(isEmailValid && isPasswordValid);
4041
};
4142

42-
useEffect(() => {
43-
if (loginState.ok === true) {
44-
setError('');
45-
router.push('/');
46-
} else {
47-
const err = loginState.error as string;
48-
setError(err);
49-
}
50-
}, [loginState, router]);
51-
5243
useEffect(() => {
5344
validateForm(email, password);
5445
}, [email, password]);
5546

5647
return (
57-
<form action={Login} className={styles.container}>
48+
<form onSubmit={handleLogin} className={styles.container}>
5849
<div className={styles.fields}>
5950
<div className={styles.input_container}>
6051
<label htmlFor="email">Username</label>
6152
<input
6253
name="email"
6354
type="email"
64-
// placeholder="Username"
6555
value={email}
66-
onChange={handleEmailChange}
56+
onInput={(e: ChangeEvent<HTMLInputElement>) =>
57+
setEmail(e.target.value)
58+
}
6759
className={`${error ? styles.error : null}`}
6860
/>
6961
</div>
@@ -72,9 +64,10 @@ export default function LoginForm() {
7264
<input
7365
name="password"
7466
type="password"
75-
// placeholder="Password"
7667
value={password}
77-
onChange={handlePasswordChange}
68+
onInput={(e: ChangeEvent<HTMLInputElement>) =>
69+
setPassword(e.target.value)
70+
}
7871
className={`${error ? styles.error : null}`}
7972
/>
8073
</div>
@@ -98,9 +91,11 @@ export default function LoginForm() {
9891
/>
9992
</div>
10093
<button
101-
className={`${styles.login_button} ${isValid ? styles.valid : null}`}
94+
className={`${styles.login_button} ${
95+
valid ? null : styles.not_valid
96+
}`}
10297
type="submit"
103-
disabled={!isValid}
98+
disabled={loading || !valid}
10499
>
105100
Log in →
106101
</button>

app/(pages)/judging-app/_components/LoginPage/LoginPage.tsx renamed to app/(pages)/judges/login/page.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
import LoginForm from './LoginForm';
1+
'use client';
2+
3+
import LoginForm from './_components/LoginForm';
24
import Image from 'next/image';
3-
import styles from './LoginPage.module.scss';
5+
import styles from './page.module.scss';
46

57
export default function LoginPage() {
68
return (
@@ -15,7 +17,7 @@ export default function LoginPage() {
1517
<p>Enter your username and password.</p>
1618
</div>
1719
<div className={styles.section}>
18-
<LoginForm></LoginForm>
20+
<LoginForm />
1921
</div>
2022
</div>
2123
);

app/(pages)/judging-app/page.tsx

Lines changed: 0 additions & 11 deletions
This file was deleted.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "hackdavis-judging-app",
2+
"name": "hackdavis-hacker-hub",
33
"version": "0.1.0",
44
"private": true,
55
"scripts": {

0 commit comments

Comments
 (0)