email de mudar senha

This commit is contained in:
2026-05-05 17:12:08 +01:00
parent fc030aef60
commit b5e0d5fc8a
2 changed files with 87 additions and 15 deletions

View File

@@ -12,7 +12,7 @@ import {
import {
signInWithEmailAndPassword, createUserWithEmailAndPassword,
onAuthStateChanged, signOut, signInWithCustomToken
onAuthStateChanged, signOut, signInWithCustomToken, sendPasswordResetEmail
} from 'firebase/auth';
import {
collection, doc, onSnapshot, addDoc, updateDoc,
@@ -39,6 +39,8 @@ export default function App() {
const [sidebarOpen, setSidebarOpen] = useState(true);
const [authMode, setAuthMode] = useState('login');
const [authError, setAuthError] = useState('');
const [showForgotPasswordModal, setShowForgotPasswordModal] = useState(false);
const [forgotPasswordEmail, setForgotPasswordEmail] = useState('');
const [categoryFilter, setCategoryFilter] = useState('Todos');
const [colorFilter, setColorFilter] = useState('');
const [ageFilter, setAgeFilter] = useState('any');
@@ -723,6 +725,30 @@ export default function App() {
} finally { setLoading(false); }
};
const handleForgotPassword = () => {
setAuthError('');
setShowForgotPasswordModal(true);
};
const handleForgotPasswordSubmit = async (e) => {
e.preventDefault();
const email = forgotPasswordEmail;
if (!email) return;
setLoading(true);
setAuthError('');
try {
await sendPasswordResetEmail(auth, email);
setShowForgotPasswordModal(false);
setForgotPasswordEmail('');
setToastMessage(t('passwordResetSent') || "E-mail de recuperação enviado! Verifique a sua caixa de entrada.");
} catch (err) {
console.error(err);
setAuthError(err.message);
} finally {
setLoading(false);
}
};
const emptyTrashPermanently = async () => {
@@ -888,6 +914,13 @@ export default function App() {
<form onSubmit={handleAuth} className="space-y-4">
<input name="email" type="email" placeholder={t('emailPlaceholder')} required className="w-full p-5 rounded-2xl bg-gray-50 dark:bg-gray-800 border-none focus:ring-2 focus:ring-primary-500 outline-none font-bold" />
<input name="password" type="password" placeholder={t('passwordPlaceholder')} required className="w-full p-5 rounded-2xl bg-gray-50 dark:bg-gray-800 border-none focus:ring-2 focus:ring-primary-500 outline-none font-bold" />
{authMode === 'login' && (
<div className="text-right">
<button type="button" onClick={handleForgotPassword} className="text-[10px] font-black text-primary-500 hover:text-primary-600 uppercase tracking-widest transition-colors">
{t('forgotPassword') || 'Esqueceu-se da palavra-passe?'}
</button>
</div>
)}
<button className="w-full py-5 bg-primary-600 text-white rounded-[2rem] font-black text-lg shadow-2xl hover:scale-[1.02] active:scale-95 transition-all">
{authMode === 'login' ? t('loginBtn') : t('registerBtn')}
</button>
@@ -900,6 +933,25 @@ export default function App() {
</div>
</div>
</Card>
{/* Modal de Forgot Password */}
{showForgotPasswordModal && (
<div className="fixed inset-0 z-[200] flex items-center justify-center bg-black/60 backdrop-blur-sm p-6" onClick={() => setShowForgotPasswordModal(false)}>
<Card className="w-full max-w-md p-8 animate-in zoom-in-95" darkMode={darkMode} onClick={e => e.stopPropagation()}>
<h3 className="text-2xl font-black mb-4 text-center text-inherit">{t('forgotPassword')}</h3>
<p className="text-center opacity-70 mb-8 text-sm text-inherit">{t('forgotPasswordPrompt')}</p>
<form onSubmit={handleForgotPasswordSubmit} className="space-y-4">
<input name="resetEmail" type="email" placeholder={t('emailPlaceholder')} required value={forgotPasswordEmail} onChange={e => setForgotPasswordEmail(e.target.value)} className="w-full p-5 rounded-2xl bg-gray-50 dark:bg-gray-800 border-none focus:ring-2 focus:ring-primary-500 outline-none font-bold text-inherit" />
<button type="submit" disabled={loading} className="w-full py-5 bg-primary-600 text-white rounded-[2rem] font-black text-lg shadow-2xl hover:scale-[1.02] active:scale-95 transition-all disabled:opacity-50">
{loading ? t('saving') : t('sendEmailBtn')}
</button>
</form>
<button type="button" onClick={() => setShowForgotPasswordModal(false)} className="w-full mt-6 py-4 uppercase font-black text-[10px] tracking-widest text-gray-500 hover:text-gray-900 dark:hover:text-white transition-colors">
{t('cancel')}
</button>
</Card>
</div>
)}
</div>
);
}

View File

@@ -5,9 +5,13 @@ export const translations = {
passwordPlaceholder: "Palavra-passe",
loginBtn: "ENTRAR",
registerBtn: "REGISTAR",
createAccount: "Criar Nova Conta",
haveAccount: "Já Tenho Conta",
authErrorDisabled: "O login por e-mail está desativado.",
createAccount: "Criar Conta",
haveAccount: "Já tenho conta",
authErrorDisabled: "Este método de login está desativado na base de dados.",
forgotPassword: "Esqueceu-se da palavra-passe?",
forgotPasswordPrompt: "Introduza o seu e-mail para recuperar a palavra-passe:",
passwordResetSent: "E-mail de recuperação enviado! Verifique a sua caixa de entrada.",
sendEmailBtn: "Enviar Email",
dashboard: "Painel",
closet: "Armário",
laundry: "Lavandaria",
@@ -195,9 +199,13 @@ export const translations = {
passwordPlaceholder: "Password",
loginBtn: "LOGIN",
registerBtn: "REGISTER",
createAccount: "Create New Account",
haveAccount: "I Already Have an Account",
authErrorDisabled: "Email login is disabled.",
createAccount: "Create Account",
haveAccount: "I already have an account",
authErrorDisabled: "This login method is disabled in the database.",
forgotPassword: "Forgot password?",
forgotPasswordPrompt: "Enter your email to reset your password:",
passwordResetSent: "Password reset email sent! Check your inbox.",
sendEmailBtn: "Send Email",
dashboard: "Dashboard",
closet: "Closet",
laundry: "Laundry",
@@ -385,9 +393,13 @@ export const translations = {
passwordPlaceholder: "Contraseña",
loginBtn: "ENTRAR",
registerBtn: "REGISTRAR",
createAccount: "Crear Nueva Cuenta",
haveAccount: "Ya Tengo Cuenta",
authErrorDisabled: "El inicio de sesión por correo electrónico está desactivado.",
createAccount: "Crear Cuenta",
haveAccount: "Ya tengo cuenta",
authErrorDisabled: "Este método de inicio de sesión está desactivado en la base de datos.",
forgotPassword: "¿Olvidaste tu contraseña?",
forgotPasswordPrompt: "Introduce tu correo electrónico para recuperar la contraseña:",
passwordResetSent: "¡Correo de recuperación enviado! Revisa tu bandeja de entrada.",
sendEmailBtn: "Enviar Correo",
dashboard: "Panel",
closet: "Armario",
laundry: "Lavandería",
@@ -575,9 +587,13 @@ export const translations = {
passwordPlaceholder: "Mot de passe",
loginBtn: "CONNEXION",
registerBtn: "S'INSCRIRE",
createAccount: "Créer un Nouveau Compte",
haveAccount: "J'ai Déjà un Compte",
authErrorDisabled: "La connexion par e-mail est désactivée.",
createAccount: "Créer un Compte",
haveAccount: "J'ai déjà un compte",
authErrorDisabled: "Cette méthode de connexion est désactivée dans la base de données.",
forgotPassword: "Mot de passe oublié ?",
forgotPasswordPrompt: "Entrez votre e-mail pour réinitialiser votre mot de passe :",
passwordResetSent: "E-mail de réinitialisation envoyé ! Vérifiez votre boîte de réception.",
sendEmailBtn: "Envoyer l'E-mail",
dashboard: "Tableau de bord",
closet: "Placard",
laundry: "Blanchisserie",
@@ -765,9 +781,13 @@ export const translations = {
passwordPlaceholder: "Passwort",
loginBtn: "ANMELDEN",
registerBtn: "REGISTRIEREN",
createAccount: "Neues Konto erstellen",
createAccount: "Konto Erstellen",
haveAccount: "Ich habe bereits ein Konto",
authErrorDisabled: "E-Mail-Anmeldung ist deaktiviert.",
authErrorDisabled: "Diese Anmeldemethode ist in der Datenbank deaktiviert.",
forgotPassword: "Passwort vergessen?",
forgotPasswordPrompt: "Gib deine E-Mail-Adresse ein, um dein Passwort zurückzusetzen:",
passwordResetSent: "E-mail zum Zurücksetzen des Passworts gesendet! Überprüfe deinen Posteingang.",
sendEmailBtn: "E-Mail Senden",
dashboard: "Startseite",
closet: "Schrank",
laundry: "Wäsche",