Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@ import 'react-toastify/dist/ReactToastify.css';
import LandingPage from "./components/landing";
import ConfigurationPage from "./components/configuration";
import DocumentationPage from "./components/documentation";
import LoginPage from "./components/login";
import PasswordResetPage from "./components/password-reset";

const App: React.FC = () => {
return (
<Router>
<div className="min-h-screen w-full">
<Routes>
<Route path="/" element={<LandingPage />} />
<Route path="/login" element={<LoginPage />} />
<Route path="/password_reset" element={<PasswordResetPage />} />
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Route paths in this app are otherwise lowercase without underscores (e.g., /login, /configure, /documentation). Using /password_reset introduces an inconsistent URL pattern; consider renaming to a hyphenated path like /password-reset (and update any Link targets accordingly).

Suggested change
<Route path="/password_reset" element={<PasswordResetPage />} />
<Route path="/password-reset" element={<PasswordResetPage />} />

Copilot uses AI. Check for mistakes.
<Route path="/configure" element={<ConfigurationPage />} />
<Route path="/documentation" element={<DocumentationPage />} />
</Routes>
Expand Down
167 changes: 167 additions & 0 deletions src/components/login/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
import React, { useState } from "react";
import { Link } from "react-router-dom";
import { LogIn, UserPlus, Eye, EyeOff } from "lucide-react";

const LoginPage: React.FC = () => {
const [isLogin, setIsLogin] = useState(true);
const [firstName, setFirstName] = useState("");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const [showPassword, setShowPassword] = useState(false);
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
const passwordsMatch = isLogin || !confirmPassword || password === confirmPassword;

const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (isLogin) {
console.log("Login attempt:", { email, password });
} else {
if (password !== confirmPassword) {
return;
}

console.log("Register attempt:", { firstName, email, password, confirmPassword });
Comment on lines +18 to +24
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid logging credentials to the browser console. console.log here includes the user's password (and confirmPassword), which can leak sensitive data via logs, shared devices, or monitoring tools. Remove these logs and route the data through your auth flow (or log only non-sensitive, redacted metadata if needed).

Suggested change
console.log("Login attempt:", { email, password });
} else {
if (password !== confirmPassword) {
return;
}
console.log("Register attempt:", { firstName, email, password, confirmPassword });
console.log("Login attempt:", { email });
} else {
if (password !== confirmPassword) {
return;
}
console.log("Register attempt:", { firstName, email });

Copilot uses AI. Check for mistakes.
}
};

const togglePanel = () => {
setIsLogin(!isLogin);
setFirstName("");
setEmail("");
setPassword("");
setConfirmPassword("");
setShowPassword(false);
setShowConfirmPassword(false);
};

return (
<div className="flex min-h-screen items-center justify-center bg-gray-900 p-4">
<div className="w-full max-w-md space-y-8 rounded-xl bg-gray-800 p-8 shadow-lg border border-gray-700 transition-all duration-500">
<div className="text-center">
<div className="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-indigo-600 shadow-md">
{isLogin ? <LogIn className="h-6 w-6 text-white" /> : <UserPlus className="h-6 w-6 text-white" />}
</div>
<h2 className="mt-6 text-3xl font-bold tracking-tight text-white">
{isLogin ? "Acessar Prisma" : "Criar sua conta"}
</h2>
</div>

<form className="mt-8 space-y-6" onSubmit={handleSubmit}>
<div className="space-y-4 rounded-md">
{!isLogin && (
<div className="animate-in fade-in slide-in-from-top-2 duration-300">
<label className="text-sm font-medium text-gray-300">Primeiro Nome</label>
<input
type="text"
required={!isLogin}
className="mt-1 block w-full rounded-md border border-gray-600 bg-gray-700 px-3 py-2 text-white placeholder-gray-400 focus:border-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 sm:text-sm transition-all"
placeholder="Seu nome"
value={firstName}
onChange={(e) => setFirstName(e.target.value)}
/>
</div>
)}

<div>
<label className="text-sm font-medium text-gray-300">Email</label>
<input
type="email"
required
className="mt-1 block w-full rounded-md border border-gray-600 bg-gray-700 px-3 py-2 text-white placeholder-gray-400 focus:border-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 sm:text-sm transition-all"
placeholder="seu@email.com"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</div>

<div>
<div className="flex items-center justify-between">
<label className="text-sm font-medium text-gray-300">Senha</label>
{isLogin && (
<Link to="/password_reset" className="text-xs text-indigo-400 hover:text-indigo-300 transition-colors">
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This link points to /password_reset, which is an inconsistent path style compared to the other routes. If the route is renamed to match the app's convention (e.g., /password-reset), update this to value as well.

Suggested change
<Link to="/password_reset" className="text-xs text-indigo-400 hover:text-indigo-300 transition-colors">
<Link to="/password-reset" className="text-xs text-indigo-400 hover:text-indigo-300 transition-colors">

Copilot uses AI. Check for mistakes.
Esqueceu a senha?
</Link>
)}
</div>
<div className="relative mt-1">
<input
type={showPassword ? "text" : "password"}
required
className="block w-full rounded-md border border-gray-600 bg-gray-700 px-3 py-2 pr-10 text-white placeholder-gray-400 focus:border-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 sm:text-sm transition-all"
placeholder="••••••••"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<button
type="button"
onClick={() => setShowPassword(!showPassword)}
className="absolute inset-y-0 right-0 flex items-center pr-3 text-gray-400 hover:text-indigo-400 transition-colors"
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The show/hide password toggle button is icon-only and lacks an accessible name. Add an aria-label (e.g., "Mostrar senha" / "Ocultar senha") and consider aria-pressed to convey state to screen readers.

Suggested change
className="absolute inset-y-0 right-0 flex items-center pr-3 text-gray-400 hover:text-indigo-400 transition-colors"
className="absolute inset-y-0 right-0 flex items-center pr-3 text-gray-400 hover:text-indigo-400 transition-colors"
aria-label={showPassword ? "Ocultar senha" : "Mostrar senha"}
aria-pressed={showPassword}

Copilot uses AI. Check for mistakes.
>
{showPassword ? <EyeOff className="h-5 w-5" /> : <Eye className="h-5 w-5" />}
</button>
</div>
</div>

{!isLogin && (
<div className="animate-in fade-in slide-in-from-top-2 duration-300">
<label className="text-sm font-medium text-gray-300">Confirmar Senha</label>
<div className="relative mt-1">
<input
type={showConfirmPassword ? "text" : "password"}
required={!isLogin}
className={`block w-full rounded-md border bg-gray-700 px-3 py-2 pr-10 text-white placeholder-gray-400 focus:outline-none focus:ring-2 sm:text-sm transition-all ${
passwordsMatch
? 'border-gray-600 focus:border-indigo-500 focus:ring-indigo-500'
: 'border-red-500 focus:ring-red-500/50'
}`}
placeholder="••••••••"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
/>
<button
type="button"
onClick={() => setShowConfirmPassword(!showConfirmPassword)}
className="absolute inset-y-0 right-0 flex items-center pr-3 text-gray-400 hover:text-indigo-400 transition-colors"
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The show/hide confirm password toggle button is icon-only and lacks an accessible name. Add an aria-label (e.g., "Mostrar confirmação de senha" / "Ocultar confirmação de senha") and consider aria-pressed to convey state.

Suggested change
className="absolute inset-y-0 right-0 flex items-center pr-3 text-gray-400 hover:text-indigo-400 transition-colors"
className="absolute inset-y-0 right-0 flex items-center pr-3 text-gray-400 hover:text-indigo-400 transition-colors"
aria-label={showConfirmPassword ? "Ocultar confirmação de senha" : "Mostrar confirmação de senha"}
aria-pressed={showConfirmPassword}

Copilot uses AI. Check for mistakes.
>
{showConfirmPassword ? <EyeOff className="h-5 w-5" /> : <Eye className="h-5 w-5" />}
</button>
</div>
{!passwordsMatch && (
<p className="mt-1 text-xs text-red-500 animate-in fade-in duration-200">
As senhas não coincidem.
</p>
)}
</div>
)}
</div>
<button
type="submit"
disabled={!passwordsMatch}
className={`w-full py-3 px-4 rounded-lg font-semibold text-white transition-all duration-300 transform ${
passwordsMatch
? 'bg-indigo-600 hover:bg-indigo-700 shadow-lg hover:shadow-xl hover:-translate-y-0.5'
: 'bg-gray-600 cursor-not-allowed opacity-50'
}`}
>
{isLogin ? "Entrar" : "Finalizar Cadastro"}
</button>
<div className="pt-6 mt-6 border-t border-gray-700 text-center">
<p className="text-sm text-gray-400">
{isLogin ? "Não tem uma conta?" : "Já possui uma conta?"}{' '}
<button
type="button"
onClick={togglePanel}
className="font-semibold text-indigo-400 hover:text-indigo-300 transition-colors"
>
{isLogin ? "Crie sua conta aqui" : "Acesse aqui"}
</button>
</p>
</div>
</form>
</div>
</div>
);
};

export default LoginPage;
90 changes: 90 additions & 0 deletions src/components/password-reset/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import React, { useState } from "react";
import { ArrowLeft, Mail, CheckCircle } from "lucide-react";
import { Link } from "react-router-dom";

const PasswordResetPage: React.FC = () => {
const [email, setEmail] = useState("");
const [isSubmitted, setIsSubmitted] = useState(false);

const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
// logica de envio de email de recuperacao
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo/accents in the inline comment: "logica de envio de email de recuperacao" should be written with proper accents in Portuguese (e.g., "lógica de envio de e-mail de recuperação").

Suggested change
// logica de envio de email de recuperacao
// lógica de envio de e-mail de recuperação

Copilot uses AI. Check for mistakes.
console.log("Reset password attempt:", { email });
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The password reset submit handler logs the entered email. Even though it's not a password, it's still user PII and shouldn't be written to the console in production. Please remove the console.log (or replace with a non-PII debug log gated to development).

Suggested change
console.log("Reset password attempt:", { email });
if (process.env.NODE_ENV === "development") {
console.log("Reset password attempt submitted");
}

Copilot uses AI. Check for mistakes.
setIsSubmitted(true);
};
Comment on lines +9 to +14
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR description mentions success/error feedback using react-toastify, but this page currently only toggles local isSubmitted state and doesn't surface any success/error toast or handle request failures. Please either implement toast notifications around the reset request (success + error paths) or adjust the PR description to match the current behavior.

Copilot uses AI. Check for mistakes.

return (
<div className="flex min-h-screen items-center justify-center bg-gray-900 p-4">
<div className="w-full max-w-md space-y-8 rounded-xl bg-gray-800 p-8 shadow-lg border border-gray-700">
<Link
to="/login"
className="inline-flex items-center text-sm text-indigo-400 hover:text-indigo-300 transition-colors mb-4"
>
<ArrowLeft className="h-4 w-4 mr-2" />
Voltar para login
</Link>

<div className="text-center">
<div className="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-indigo-600 shadow-md">
<Mail className="h-6 w-6 text-white" />
</div>
<h2 className="mt-6 text-3xl font-bold tracking-tight text-white">
Recuperar Senha
</h2>
<p className="mt-2 text-sm text-gray-400">
{isSubmitted
? "Verifique seu email"
: "Digite seu email para receber um link de recuperação"}
</p>
</div>

{!isSubmitted ? (
<form className="mt-8 space-y-6" onSubmit={handleSubmit}>
<div>
<label className="text-sm font-medium text-gray-300">Email</label>
<input
type="email"
required
className="mt-1 block w-full rounded-md border border-gray-600 bg-gray-700 px-3 py-2 text-white placeholder-gray-400 focus:border-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 sm:text-sm transition-all"
placeholder="seu@email.com"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</div>

<button
type="submit"
className="w-full py-3 px-4 rounded-lg font-semibold text-white bg-indigo-600 hover:bg-indigo-700 shadow-lg hover:shadow-xl transition-all duration-300 transform hover:-translate-y-0.5"
>
Enviar Link de Recuperação
</button>
</form>
) : (
<div className="mt-8 space-y-6">
<div className="flex flex-col items-center justify-center space-y-4">
<CheckCircle className="h-16 w-16 text-green-500" />
<p className="text-center text-gray-300">
Enviamos um link de recuperação para <span className="font-semibold">{email}</span>
</p>
<p className="text-center text-sm text-gray-400">
Verifique sua caixa de entrada e clique no link para redefinir sua senha.
</p>
</div>

<button
onClick={() => {
setEmail("");
setIsSubmitted(false);
}}
className="w-full py-3 px-4 rounded-lg font-semibold text-white bg-indigo-600 hover:bg-indigo-700 shadow-lg hover:shadow-xl transition-all duration-300 transform hover:-translate-y-0.5"
>
Enviar outro email
</button>
</div>
)}
</div>
</div>
);
};

export default PasswordResetPage;