Skip to content

Commit 7004364

Browse files
committed
feat(auth): PAV-51 cria authService com funcoes de autenticacao
1 parent ccee4dd commit 7004364

12 files changed

Lines changed: 1026 additions & 126 deletions

File tree

frontend/index.html

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
<html lang="pt-br">
33
<head>
44
<meta charset="UTF-8" />
5-
<!--C:\Users\benev\projetos\Node\vagas-full\frontend\src\assets\logo-painel-vagas.svg-->
6-
<link rel="icon" type="image/svg+xml" href="/logo.svg" />
5+
<link rel="icon" type="image/png" href="public/icone.png" />
76
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
87

98
<script>
@@ -36,7 +35,7 @@
3635
})();
3736
</script>
3837

39-
<title>Painel de Vagas</title>
38+
<title><Cand!Date!></title>
4039
</head>
4140
<body>
4241
<div id="root"></div>

frontend/public/icone.png

5.3 KB
Loading

frontend/src/components/login/LeftSide.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Image } from "@unpic/react"
2-
import { Instagram, Linkedin, Search, Bell, TrendingUp } from "lucide-react"
2+
import { Bell, Instagram, Linkedin, Search, TrendingUp } from "lucide-react"
33

44
export default function LeftSide() {
55
return (
@@ -11,7 +11,7 @@ export default function LeftSide() {
1111
alt="Profissionais de tecnologia"
1212
layout="fullWidth"
1313
className="h-full w-full object-cover opacity-[0.85] dark:opacity-30 mix-blend-multiply dark:mix-blend-luminosity"
14-
priority
14+
priority={true}
1515
/>
1616
<div className="absolute inset-0 bg-gradient-to-tr from-blue-500/10 via-purple-500/5 to-transparent pointer-events-none" />
1717
</div>
@@ -77,4 +77,4 @@ export default function LeftSide() {
7777
</div>
7878
</aside>
7979
)
80-
}
80+
}

frontend/src/components/login/RegisterSide.tsx

Lines changed: 75 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
import { useState, FormEvent } from "react";
2-
import { Eye, EyeOff, ArrowLeft } from "lucide-react";
1+
/* eslint-disable @typescript-eslint/no-explicit-any */
2+
import { register } from "@/services/authService"; // ← MUDE para register
33
import { Image } from "@unpic/react";
44
import { motion } from "framer-motion";
5+
import { ArrowLeft, Eye, EyeOff } from "lucide-react";
6+
import { FormEvent, useState } from "react";
57
import PhoneInput from "react-phone-number-input";
68
import "react-phone-number-input/style.css";
79

@@ -59,6 +61,9 @@ export default function RegisterSide() {
5961
const [telefoneError, setTelefoneError] = useState("");
6062
const [passwordError, setPasswordError] = useState("");
6163
const [cpfError, setCpfError] = useState("");
64+
65+
const [isLoading, setIsLoading] = useState(false);
66+
const [apiError, setApiError] = useState("");
6267

6368
const handleRevealPassword = () => setShowPassword((prev) => !prev);
6469

@@ -70,41 +75,67 @@ export default function RegisterSide() {
7075
return `${digits.slice(0, 3)}.${digits.slice(3, 6)}.${digits.slice(6, 9)}-${digits.slice(9)}`;
7176
};
7277

73-
const handleSubmit = (e: FormEvent) => {
78+
const handleSubmit = async (e: FormEvent) => {
7479
e.preventDefault();
7580
setNomeError("");
7681
setEmailError("");
7782
setTelefoneError("");
7883
setPasswordError("");
7984
setCpfError("");
85+
setApiError("");
8086

8187
let isValid = true;
8288

83-
if (!nome) { setNomeError("O campo de nome é obrigatório."); isValid = false; }
89+
if (!nome) {
90+
setNomeError("O campo de nome é obrigatório.");
91+
isValid = false;
92+
}
8493

8594
if (!email) {
86-
setEmailError("O campo de e-mail é obrigatório."); isValid = false;
95+
setEmailError("O campo de e-mail é obrigatório.");
96+
isValid = false;
8797
} else {
8898
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
89-
if (!emailRegex.test(email)) { setEmailError("Por favor, insira um e-mail válido."); isValid = false; }
99+
if (!emailRegex.test(email)) {
100+
setEmailError("Por favor, insira um e-mail válido.");
101+
isValid = false;
102+
}
90103
}
91104

92-
if (!telefone) { setTelefoneError("O campo de telefone é obrigatório."); isValid = false; }
105+
if (!telefone) {
106+
setTelefoneError("O campo de telefone é obrigatório.");
107+
isValid = false;
108+
}
93109

94110
if (!password) {
95-
setPasswordError("O campo de senha é obrigatório."); isValid = false;
111+
setPasswordError("O campo de senha é obrigatório.");
112+
isValid = false;
96113
} else if (password.length < 6) {
97-
setPasswordError("A senha precisa conter pelo menos 6 caracteres."); isValid = false;
114+
setPasswordError("A senha precisa conter pelo menos 6 caracteres.");
115+
isValid = false;
98116
}
99117

100-
if (!cpf) {
101-
setCpfError("O campo de CPF é obrigatório."); isValid = false;
102-
} else if (cpf.replace(/\D/g, "").length < 11) {
103-
setCpfError("Por favor, insira um CPF válido."); isValid = false;
118+
if (cpf && cpf.replace(/\D/g, "").length > 0 && cpf.replace(/\D/g, "").length !== 11) {
119+
setCpfError("CPF inválido. Deve conter 11 dígitos.");
120+
isValid = false;
104121
}
105122

106123
if (isValid) {
107-
console.log("Cadastro válido!", { nome, email, telefone, password, cpf });
124+
setIsLoading(true);
125+
try {
126+
const result = await register({
127+
email: email,
128+
password: password,
129+
name: nome,
130+
});
131+
console.log("Cadastro bem sucedido:", result);
132+
window.location.href = "/login?registered=true";
133+
} catch (error: any) {
134+
console.error("Erro no cadastro:", error);
135+
setApiError(error.message || "Erro ao cadastrar. Tente novamente.");
136+
} finally {
137+
setIsLoading(false);
138+
}
108139
}
109140
};
110141

@@ -144,6 +175,12 @@ export default function RegisterSide() {
144175

145176
<form className="relative z-10 space-y-5 w-full max-w-2xl mx-auto my-8" onSubmit={handleSubmit}>
146177

178+
{apiError && (
179+
<div className="p-3 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-xl">
180+
<p className="text-sm text-red-600 dark:text-red-400 text-center">{apiError}</p>
181+
</div>
182+
)}
183+
147184
<div>
148185
<label htmlFor="nome" className="block text-sm font-semibold text-gray-700 dark:text-neutral-300 mb-1.5">
149186
Nome
@@ -153,10 +190,11 @@ export default function RegisterSide() {
153190
type="text"
154191
value={nome}
155192
onChange={(e) => setNome(e.target.value)}
156-
placeholder="Bene Santos"
193+
placeholder="benevanio"
194+
disabled={isLoading}
157195
className={`w-full px-4 py-3.5 rounded-xl border bg-white/80 dark:bg-neutral-800/80 backdrop-blur-sm text-gray-900 dark:text-white placeholder-gray-400 dark:placeholder-neutral-500 focus:outline-none focus:ring-2 transition-all shadow-sm ${
158196
nomeError ? "border-red-500 focus:ring-red-500" : "border-gray-200 dark:border-neutral-700 focus:ring-blue-500 focus:border-transparent"
159-
}`}
197+
} ${isLoading ? "opacity-50 cursor-not-allowed" : ""}`}
160198
/>
161199
{nomeError && <p className="mt-1.5 text-xs text-red-500 font-medium">{nomeError}</p>}
162200
</div>
@@ -170,10 +208,11 @@ export default function RegisterSide() {
170208
type="email"
171209
value={email}
172210
onChange={(e) => setEmail(e.target.value)}
173-
placeholder="lbene17@gmail.com"
211+
placeholder="benevanio@dev.com.br"
212+
disabled={isLoading}
174213
className={`w-full px-4 py-3.5 rounded-xl border bg-white/80 dark:bg-neutral-800/80 backdrop-blur-sm text-gray-900 dark:text-white placeholder-gray-400 dark:placeholder-neutral-500 focus:outline-none focus:ring-2 transition-all shadow-sm ${
175214
emailError ? "border-red-500 focus:ring-red-500" : "border-gray-200 dark:border-neutral-700 focus:ring-blue-500 focus:border-transparent"
176-
}`}
215+
} ${isLoading ? "opacity-50 cursor-not-allowed" : ""}`}
177216
/>
178217
{emailError && <p className="mt-1.5 text-xs text-red-500 font-medium">{emailError}</p>}
179218
</div>
@@ -184,12 +223,13 @@ export default function RegisterSide() {
184223
</label>
185224
<div className={`flex rounded-xl border bg-white/80 dark:bg-neutral-800/80 backdrop-blur-sm shadow-sm overflow-hidden transition-all focus-within:ring-2 ${
186225
telefoneError ? "border-red-500 focus-within:ring-red-500" : "border-gray-200 dark:border-neutral-700 focus-within:ring-blue-500"
187-
}`}>
226+
} ${isLoading ? "opacity-50" : ""}`}>
188227
<PhoneInput
189228
international
190229
defaultCountry="BR"
191230
value={telefone}
192231
onChange={setTelefone}
232+
disabled={isLoading}
193233
className="w-full px-4 py-3.5 text-gray-900 dark:text-white bg-transparent focus:outline-none phone-input-custom"
194234
placeholder="(34) 23456-7890"
195235
/>
@@ -208,13 +248,15 @@ export default function RegisterSide() {
208248
value={password}
209249
onChange={(e) => setPassword(e.target.value)}
210250
placeholder="Ex: ••••••••••••"
251+
disabled={isLoading}
211252
className={`w-full px-4 py-3.5 rounded-xl border bg-white/80 dark:bg-neutral-800/80 backdrop-blur-sm text-gray-900 dark:text-white placeholder-gray-400 dark:placeholder-neutral-500 focus:outline-none focus:ring-2 transition-all shadow-sm ${
212253
passwordError ? "border-red-500 focus:ring-red-500" : "border-gray-200 dark:border-neutral-700 focus:ring-blue-500 focus:border-transparent"
213-
}`}
254+
} ${isLoading ? "opacity-50 cursor-not-allowed" : ""}`}
214255
/>
215256
<button
216257
type="button"
217258
onClick={handleRevealPassword}
259+
disabled={isLoading}
218260
className="absolute inset-y-0 right-0 pr-4 flex items-center text-gray-400 dark:text-neutral-500 hover:text-blue-500 dark:hover:text-blue-400 transition-colors"
219261
>
220262
{showPassword ? <EyeOff className="h-5 w-5" /> : <Eye className="h-5 w-5" />}
@@ -225,29 +267,31 @@ export default function RegisterSide() {
225267

226268
<div>
227269
<label htmlFor="cpf" className="block text-sm font-semibold text-gray-700 dark:text-neutral-300 mb-1.5">
228-
CPF
270+
CPF <span className="text-gray-400 dark:text-neutral-500 text-xs font-normal">(opcional)</span>
229271
</label>
230272
<input
231273
id="cpf"
232274
type="text"
233275
value={cpf}
234276
onChange={(e) => setCpf(formatCpf(e.target.value))}
235277
placeholder="091.000.000-00"
278+
disabled={isLoading}
236279
className={`w-full px-4 py-3.5 rounded-xl border bg-white/80 dark:bg-neutral-800/80 backdrop-blur-sm text-gray-900 dark:text-white placeholder-gray-400 dark:placeholder-neutral-500 focus:outline-none focus:ring-2 transition-all shadow-sm ${
237280
cpfError ? "border-red-500 focus:ring-red-500" : "border-gray-200 dark:border-neutral-700 focus:ring-blue-500 focus:border-transparent"
238-
}`}
281+
} ${isLoading ? "opacity-50 cursor-not-allowed" : ""}`}
239282
/>
240283
{cpfError && <p className="mt-1.5 text-xs text-red-500 font-medium">{cpfError}</p>}
241284
</div>
242285

243286
<motion.button
244287
type="submit"
245-
whileHover={{ scale: 1.01 }}
246-
whileTap={{ scale: 0.99 }}
247-
className="w-full bg-gradient-to-r from-blue-600 via-purple-600 to-teal-600 hover:opacity-95 text-white py-3.5 px-4 rounded-xl font-bold text-base focus:outline-none focus:ring-2 focus:ring-blue-500 transition-all shadow-md shadow-blue-500/10 cursor-pointer"
288+
disabled={isLoading}
289+
whileHover={{ scale: isLoading ? 1 : 1.01 }}
290+
whileTap={{ scale: isLoading ? 1 : 0.99 }}
291+
className="w-full bg-gradient-to-r from-blue-600 via-purple-600 to-teal-600 hover:opacity-95 text-white py-3.5 px-4 rounded-xl font-bold text-base focus:outline-none focus:ring-2 focus:ring-blue-500 transition-all shadow-md shadow-blue-500/10 cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed"
248292
>
249-
Cadastrar
250-
</motion.button>
293+
{isLoading ? "Cadastrando..." : "Cadastrar"}
294+
</motion.button>
251295
</form>
252296

253297
<div className="relative z-10 w-full max-w-2xl mx-auto">
@@ -260,15 +304,14 @@ export default function RegisterSide() {
260304
</div>
261305
</div>
262306

263-
{/* Botões Sociais Atualizados com Hover translúcido e bordas combinando */}
264307
<div className="grid grid-cols-3 gap-4">
265-
<button className="flex justify-center items-center py-3 px-4 border border-gray-200 dark:border-neutral-800 rounded-xl bg-white/50 dark:bg-neutral-800/50 hover:bg-gray-50 dark:hover:bg-neutral-700/50 transition-all shadow-sm cursor-pointer">
308+
<button type="button" disabled={isLoading} className="flex justify-center items-center py-3 px-4 border border-gray-200 dark:border-neutral-800 rounded-xl bg-white/50 dark:bg-neutral-800/50 hover:bg-gray-50 dark:hover:bg-neutral-700/50 transition-all shadow-sm cursor-pointer disabled:opacity-50">
266309
<Image src="/google.png" alt="Google" width={20} height={20} className="object-contain" />
267310
</button>
268-
<button className="flex justify-center items-center py-3 px-4 border border-gray-200 dark:border-neutral-800 rounded-xl bg-white/50 dark:bg-neutral-800/50 hover:bg-gray-50 dark:hover:bg-neutral-700/50 transition-all shadow-sm cursor-pointer">
311+
<button type="button" disabled={isLoading} className="flex justify-center items-center py-3 px-4 border border-gray-200 dark:border-neutral-800 rounded-xl bg-white/50 dark:bg-neutral-800/50 hover:bg-gray-50 dark:hover:bg-neutral-700/50 transition-all shadow-sm cursor-pointer disabled:opacity-50">
269312
<Image src="/facebook.png" alt="Facebook" width={20} height={20} className="object-contain" />
270313
</button>
271-
<button className="flex justify-center items-center py-3 px-4 border border-gray-200 dark:border-neutral-800 rounded-xl bg-white/50 dark:bg-neutral-800/50 hover:bg-gray-50 dark:hover:bg-neutral-700/50 transition-all shadow-sm cursor-pointer">
314+
<button type="button" disabled={isLoading} className="flex justify-center items-center py-3 px-4 border border-gray-200 dark:border-neutral-800 rounded-xl bg-white/50 dark:bg-neutral-800/50 hover:bg-gray-50 dark:hover:bg-neutral-700/50 transition-all shadow-sm cursor-pointer disabled:opacity-50">
272315
<svg className="h-5 w-5 fill-gray-900 dark:fill-white transition-colors" viewBox="0 0 24 24">
273316
<path d="M18.71 19.5c-.83 1.24-1.71 2.45-3.05 2.47-1.34.03-1.77-.79-3.29-.79-1.53 0-2 .77-3.27.82-1.31.05-2.3-1.32-3.14-2.53C4.25 17 2.94 12.45 4.7 9.39c.87-1.52 2.43-2.48 4.12-2.51 1.28-.02 2.5.87 3.29.87.78 0 2.26-1.07 3.81-.91.65.03 2.47.26 3.64 1.98-.09.06-2.17 1.28-2.15 3.81.03 3.02 2.65 4.03 2.68 4.04-.03.07-.42 1.44-1.38 2.83M15.97 4.17c.66-.81 1.11-1.93.99-3.06-1 .04-2.21.67-2.93 1.49-.62.69-1.16 1.84-1.01 2.96 1.12.09 2.27-.58 2.95-1.39z"/>
274317
</svg>
@@ -278,4 +321,4 @@ export default function RegisterSide() {
278321

279322
</main>
280323
);
281-
}
324+
}

0 commit comments

Comments
 (0)