Skip to content

Commit 7f5b035

Browse files
committed
feat(#69): Implement user registration form with validation and role selection
1 parent ac4db31 commit 7f5b035

File tree

1 file changed

+164
-63
lines changed

1 file changed

+164
-63
lines changed

src/app/register/page.tsx

Lines changed: 164 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,174 @@
1-
// src/app/register/page.tsx
2-
import Image from 'next/image'
3-
import Link from 'next/link'
4-
import styles from './register.module.css'
1+
'use client';
2+
3+
import { useState } from 'react';
4+
import { useRouter } from 'next/navigation';
5+
import Link from 'next/link';
6+
import styles from './register.module.css';
7+
import Image from 'next/image';
58

69
export default function RegisterPage() {
7-
return (
8-
<div className={styles.pageContainer}>
9-
<div className={styles.header}>
10-
<Image src='/images/d20.png' alt='EasyCrit Logo' width={25} height={25} className={styles.logo} />
11-
<span className={styles.headerTitle}>EasyCrit</span>
12-
</div>
10+
const [email, setEmail] = useState('');
11+
const [password, setPassword] = useState('');
12+
const [confirmPassword, setConfirmPassword] = useState('');
13+
const [username, setUsername] = useState('');
14+
const [role, setRole] = useState('master');
15+
const [error, setError] = useState('');
16+
const [loading, setLoading] = useState(false);
17+
18+
const router = useRouter();
19+
20+
const handleSubmit = async (event: React.FormEvent) => {
21+
event.preventDefault();
22+
setError('');
23+
setLoading(true);
1324

14-
<div className={styles.mainContainer}>
15-
<div className={styles.blackContainer}>
16-
<form className={styles.formWrapper}>
17-
<h2 className={styles.greeting}>Saudações, aventureiro!</h2>
25+
if (password !== confirmPassword) {
26+
setError('As senhas não coincidem.');
27+
setLoading(false);
28+
return;
29+
}
1830

19-
<div className={styles.inputGroup}>
20-
<label htmlFor='email'>Email</label>
21-
<input type='email' id='email' className={styles.inputField} placeholder='example@email.com' />
22-
</div>
31+
try {
32+
const response = await fetch('http://localhost:8001/users/', {
33+
method: 'POST',
34+
headers: {
35+
'Content-Type': 'application/json',
36+
},
37+
body: JSON.stringify({
38+
email: email,
39+
password: password,
40+
username: username,
41+
role: role,
42+
}),
43+
});
2344

24-
<div className={styles.inputGroup}>
25-
<label htmlFor='nickname'>Apelido</label>
26-
<input type='text' id='nickname' className={styles.inputField} placeholder='Seu Apelido' />
27-
</div>
45+
if (!response.ok) {
46+
const errorData = await response.json();
47+
setError(errorData.detail || 'Erro ao cadastrar usuário.');
48+
} else {
49+
const userData = await response.json();
50+
console.log('Usuário cadastrado com sucesso:', userData);
51+
router.push('/login');
52+
}
53+
} catch (err) {
54+
console.error('Erro na requisição:', err);
55+
setError('Ocorreu um erro ao tentar conectar com o servidor.');
56+
} finally {
57+
setLoading(false);
58+
}
59+
};
2860

29-
<div className={styles.inputGroup}>
30-
<label htmlFor='password'>Senha</label>
31-
<input type='password' id='password' className={styles.inputField} placeholder='••••••••' />
32-
</div>
61+
return (
62+
<div className={styles.pageContainer}>
63+
<header className={styles.header}>
64+
<h1 className={styles.headerTitle}>EASYCRIT</h1>
65+
</header>
66+
<div className={styles.mainContainer}>
67+
<div className={styles.blackContainer}>
68+
<div className={styles.formWrapper}>
69+
<h2 className={styles.greeting}>Crie sua conta</h2>
70+
<form onSubmit={handleSubmit}>
71+
<div className={styles.inputGroup}>
72+
<label htmlFor='username'>Nome de Usuário</label>
73+
<input
74+
type='text'
75+
id='username'
76+
className={styles.inputField}
77+
placeholder='Seu nome de usuário'
78+
value={username}
79+
onChange={(e) => setUsername(e.target.value)}
80+
required
81+
/>
82+
</div>
83+
<div className={styles.inputGroup}>
84+
<label htmlFor='email'>Email</label>
85+
<input
86+
type='email'
87+
id='email'
88+
className={styles.inputField}
89+
placeholder='Seu email'
90+
value={email}
91+
onChange={(e) => setEmail(e.target.value)}
92+
required
93+
/>
94+
</div>
95+
<div className={styles.inputGroup}>
96+
<label htmlFor='password'>Senha</label>
97+
<input
98+
type='password'
99+
id='password'
100+
className={styles.inputField}
101+
placeholder='••••••••'
102+
value={password}
103+
onChange={(e) => setPassword(e.target.value)}
104+
required
105+
/>
106+
</div>
107+
<div className={styles.inputGroup}>
108+
<label htmlFor='confirm-password'>Confirmar Senha</label>
109+
<input
110+
type='password'
111+
id='confirm-password'
112+
className={styles.inputField}
113+
placeholder='••••••••'
114+
value={confirmPassword}
115+
onChange={(e) => setConfirmPassword(e.target.value)}
116+
required
117+
/>
118+
</div>
33119

34-
<div className={styles.inputGroup}>
35-
<label htmlFor='confirm-password'>Confirmar Senha</label>
36-
<input type='password' id='confirm-password' className={styles.inputField} placeholder='••••••••' />
37-
</div>
120+
<div className={styles.adventureChoice}>
121+
<div className={styles.chooseAdventure}>Escolha sua aventura</div>
122+
<div className={styles.roles}>
123+
<label className={styles.roleOption}>
124+
<input
125+
type='radio'
126+
name='role'
127+
value='master'
128+
className={styles.radioInput}
129+
checked={role === 'master'}
130+
onChange={() => setRole('master')}
131+
/>
132+
<Image
133+
src='/mestre-icon.svg'
134+
alt='Dungeon Master'
135+
width={40}
136+
height={40}
137+
className={styles.roleImage}
138+
/>
139+
<span className={styles.roleLabel}>Mestre</span>
140+
</label>
141+
<label className={styles.roleOption}>
142+
<input
143+
type='radio'
144+
name='role'
145+
value='player'
146+
className={styles.radioInput}
147+
checked={role === 'player'}
148+
onChange={() => setRole('player')}
149+
/>
150+
<Image src='/jogador-icon.svg' alt='Player' width={40} height={40} className={styles.roleImage} />
151+
<span className={styles.roleLabel}>Jogador</span>
152+
</label>
153+
</div>
154+
</div>
38155

39-
<div className={styles.adventureChoice}>
40-
<div className={styles.chooseAdventure}>Escolha sua aventura</div>
41-
<div className={styles.roles}>
42-
<label className={styles.roleOption}>
43-
<input type='radio' name='role' value='master' className={styles.radioInput} defaultChecked />
44-
<Image
45-
src='/mestre-icon.svg'
46-
alt='Dungeon Master'
47-
width={40}
48-
height={40}
49-
className={styles.roleImage}
50-
/>
51-
<span className={styles.roleLabel}>Mestre</span>
52-
</label>
53-
<label className={styles.roleOption}>
54-
<input type='radio' name='role' value='Player' className={styles.radioInput} />
55-
<Image src='/jogador-icon.svg' alt='Player' width={40} height={40} className={styles.roleImage} />
56-
<span className={styles.roleLabel}>Jogador</span>
57-
</label>
58-
</div>
59-
</div>
156+
{/* Exibe mensagem de erro, se houver */}
157+
{error && <p style={{ color: 'red', textAlign: 'center', marginTop: '1rem' }}>{error}</p>}
60158

61-
<button type='submit' className={styles.submitButton}>
62-
CADASTRAR-SE
63-
</button>
159+
{/* Botão de envio, desabilitado durante o carregamento */}
160+
<button type='submit' className={styles.submitButton} disabled={loading}>
161+
{loading ? 'CADASTRANDO...' : 'CADASTRAR-SE'}
162+
</button>
64163

65-
<p className={styles.AccountNew}>
66-
<Link href='/login'>Já tem uma conta?</Link>
67-
</p>
68-
</form>
69-
</div>
70-
</div>
71-
</div>
72-
)
73-
}
164+
{/* Link para a página de login */}
165+
<p className={styles.AccountNew}>
166+
<Link href='/login'>Já tem uma conta?</Link>
167+
</p>
168+
</form>
169+
</div>
170+
</div>
171+
</div>
172+
</div>
173+
);
174+
}

0 commit comments

Comments
 (0)