feat: sessão #3 — lib (db/auth/email/validations), API routes, NextAuth v5, middleware, páginas account/shelters/shelter-dashboard, Prisma v7 fix
This commit is contained in:
119
app/auth/forgot-password/page.tsx
Normal file
119
app/auth/forgot-password/page.tsx
Normal file
@@ -0,0 +1,119 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { PawPrint, Mail, ArrowLeft } from 'lucide-react';
|
||||
|
||||
export default function ForgotPasswordPage() {
|
||||
const [email, setEmail] = useState('');
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [sent, setSent] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setError(null);
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
// TODO: substituir por chamada real à API quando o fluxo de reset estiver implementado
|
||||
await new Promise((r) => setTimeout(r, 800));
|
||||
setSent(true);
|
||||
} catch {
|
||||
setError('Erro ao enviar email. Tenta de novo.');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (sent) {
|
||||
return (
|
||||
<div style={{ textAlign: 'center', maxWidth: '420px', padding: '48px 24px' }}>
|
||||
<div style={{ fontSize: '48px', marginBottom: '16px' }}>📬</div>
|
||||
<h1 style={{ fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: '26px', color: 'var(--soil)', marginBottom: '12px' }}>
|
||||
Email enviado!
|
||||
</h1>
|
||||
<p style={{ fontFamily: 'var(--font-body)', color: 'var(--soil-mid)', marginBottom: '28px', lineHeight: 1.6 }}>
|
||||
Se <strong>{email}</strong> estiver registado, receberás um email com instruções para repor a tua palavra-passe.
|
||||
</p>
|
||||
<Link href="/auth/login" className="btn btn-secondary" style={{ display: 'inline-flex', justifyContent: 'center', gap: '8px' }}>
|
||||
<ArrowLeft size={15} />
|
||||
Voltar ao login
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
width: '100%',
|
||||
maxWidth: '420px',
|
||||
background: 'var(--linen)',
|
||||
border: '1px solid var(--parchment)',
|
||||
borderRadius: '20px',
|
||||
padding: 'clamp(28px, 5vw, 44px)',
|
||||
boxShadow: 'var(--shadow-warm-md)',
|
||||
}}
|
||||
>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '28px' }}>
|
||||
<PawPrint size={20} style={{ color: 'var(--terra)' }} />
|
||||
<span className="logo" style={{ fontSize: '18px' }}>PawLink</span>
|
||||
</div>
|
||||
|
||||
<h1 style={{ fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: '26px', color: 'var(--soil)', marginBottom: '8px', lineHeight: 1.15 }}>
|
||||
Esqueceste a palavra-passe?
|
||||
</h1>
|
||||
<p style={{ fontFamily: 'var(--font-body)', fontSize: '14px', color: 'var(--soil-mid)', marginBottom: '28px', lineHeight: 1.55 }}>
|
||||
Introduz o teu email e enviamos um link para repor a palavra-passe.
|
||||
</p>
|
||||
|
||||
{error && (
|
||||
<div style={{ background: 'rgba(196,80,26,0.08)', border: '1px solid rgba(196,80,26,0.25)', borderRadius: '10px', padding: '12px 16px', marginBottom: '20px', fontFamily: 'var(--font-body)', fontSize: '14px', color: 'var(--terra)' }}>
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<form onSubmit={handleSubmit} noValidate style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: '6px' }}>
|
||||
<label htmlFor="forgot-email" style={{ fontFamily: 'var(--font-accent)', fontSize: '11px', letterSpacing: '0.08em', textTransform: 'uppercase', color: 'var(--soil-faint)' }}>
|
||||
Email
|
||||
</label>
|
||||
<div style={{ position: 'relative' }}>
|
||||
<Mail size={15} style={{ position: 'absolute', left: '14px', top: '50%', transform: 'translateY(-50%)', color: 'var(--soil-faint)', pointerEvents: 'none' }} />
|
||||
<input
|
||||
id="forgot-email"
|
||||
type="email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
placeholder="o.teu@email.pt"
|
||||
required
|
||||
autoComplete="email"
|
||||
style={{ width: '100%', padding: '12px 16px 12px 40px', background: 'var(--cream)', border: '1.5px solid var(--parchment)', borderRadius: '10px', fontFamily: 'var(--font-body)', fontSize: '15px', color: 'var(--soil)', outline: 'none', transition: 'border-color 180ms ease', minHeight: '48px' }}
|
||||
onFocus={(e) => (e.target.style.borderColor = 'var(--terra)')}
|
||||
onBlur={(e) => (e.target.style.borderColor = 'var(--parchment)')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
id="forgot-submit"
|
||||
type="submit"
|
||||
className="btn btn-primary"
|
||||
disabled={loading}
|
||||
style={{ width: '100%', justifyContent: 'center', opacity: loading ? 0.75 : 1, cursor: loading ? 'not-allowed' : 'pointer' }}
|
||||
aria-label="Enviar email de recuperação"
|
||||
>
|
||||
{loading ? 'A enviar…' : 'Enviar link de recuperação'}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<div style={{ marginTop: '20px', textAlign: 'center' }}>
|
||||
<Link href="/auth/login" style={{ fontFamily: 'var(--font-body)', fontSize: '14px', color: 'var(--soil-mid)', display: 'inline-flex', alignItems: 'center', gap: '6px' }}>
|
||||
<ArrowLeft size={14} />
|
||||
Voltar ao login
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user