217 lines
6.9 KiB
JavaScript
217 lines
6.9 KiB
JavaScript
import React, { useState, useEffect } from "react";
|
|
import {
|
|
checkActionCode,
|
|
confirmPasswordReset,
|
|
getAuth,
|
|
sendPasswordResetEmail,
|
|
} from "firebase/auth";
|
|
import Button from "../../pageElements/Button";
|
|
import { useSearchParams } from "react-router-dom";
|
|
|
|
const PasswordResetPage = () => {
|
|
const auth = getAuth();
|
|
const [isBusy, setIsBusy] = useState(false);
|
|
const [isCodeValid, setIsCodeValid] = useState(null);
|
|
const [email, setEmail] = useState("");
|
|
const [password, setPassword] = useState("");
|
|
const [confirmPassword, setConfirmPassword] = useState("");
|
|
const [done, setDone] = useState(false);
|
|
const [notice, setNotice] = useState("");
|
|
const [searchParams] = useSearchParams();
|
|
const mode = searchParams.get("mode");
|
|
const oobCode = searchParams.get("oobCode");
|
|
|
|
useEffect(() => {
|
|
async function handleCheckCode() {
|
|
if (!oobCode) {
|
|
setIsCodeValid(false);
|
|
return;
|
|
}
|
|
try {
|
|
await checkActionCode(auth, oobCode);
|
|
setIsCodeValid(true);
|
|
} catch (error) {
|
|
setIsCodeValid(false);
|
|
}
|
|
}
|
|
handleCheckCode();
|
|
}, [auth, oobCode]);
|
|
|
|
const handleResetPassword = async (e) => {
|
|
e.preventDefault();
|
|
if (isBusy) {
|
|
return;
|
|
}
|
|
setIsBusy(true);
|
|
setNotice("");
|
|
try {
|
|
await sendPasswordResetEmail(auth, email);
|
|
setDone(true);
|
|
} catch (error) {
|
|
if (error.code === "auth/invalid-email") {
|
|
setNotice("Invalid email.");
|
|
} else {
|
|
setNotice(`Error occured (${error.code}).`);
|
|
}
|
|
} finally {
|
|
setIsBusy(false);
|
|
}
|
|
};
|
|
|
|
const handleConfirmPasswordReset = async (e) => {
|
|
e.preventDefault();
|
|
if (isBusy) {
|
|
return;
|
|
}
|
|
if (password !== confirmPassword) {
|
|
setNotice("Passwords do not match");
|
|
return;
|
|
}
|
|
setIsBusy(true);
|
|
try {
|
|
await confirmPasswordReset(auth, oobCode, password);
|
|
setDone(true);
|
|
} catch (error) {
|
|
if (error.code === "auth/weak-password") {
|
|
setNotice("Weak password.");
|
|
} else {
|
|
setNotice(`Error occured (${error.code}).`);
|
|
}
|
|
} finally {
|
|
setIsBusy(false);
|
|
}
|
|
};
|
|
|
|
const resetMode = mode === "resetPassword" ? "resetPassword" : "enterEmail";
|
|
return (
|
|
<div className="password-reset-container">
|
|
<div className="password-reset-form-wrapper">
|
|
<div className="password-reset-form">
|
|
{resetMode === "enterEmail" ? (
|
|
<>
|
|
<div className="password-reset-header">
|
|
<h2 className="password-reset-header-text">
|
|
Enter Account Email
|
|
</h2>
|
|
</div>
|
|
{!done ? (
|
|
<form>
|
|
<div className="form-floating">
|
|
<input
|
|
type="email"
|
|
className="form-control"
|
|
id="emailInput"
|
|
placeholder="Email"
|
|
value={email}
|
|
onChange={(e) => setEmail(e.target.value)}
|
|
disabled={isBusy}
|
|
></input>
|
|
<label htmlFor="emailInput" className="form-label">
|
|
Email
|
|
</label>
|
|
</div>
|
|
<div className="alert-box">
|
|
{"" !== notice && (
|
|
<div className="password-reset-alert" role="alert">
|
|
{notice}
|
|
</div>
|
|
)}
|
|
</div>
|
|
<div className="password-reset-button-wrapper">
|
|
<Button
|
|
className="primary-button"
|
|
onClick={(e) => handleResetPassword(e)}
|
|
labelText="Submit"
|
|
disabled={isBusy}
|
|
/>
|
|
</div>
|
|
</form>
|
|
) : null}
|
|
{done && (
|
|
<div className="success-container">
|
|
<p className="reset-sent-text">
|
|
A password reset link was sent.
|
|
</p>
|
|
</div>
|
|
)}
|
|
</>
|
|
) : null}
|
|
{resetMode === "resetPassword" ? (
|
|
<>
|
|
<div className="password-reset-header">
|
|
<h2 className="password-reset-header-text">
|
|
Enter New Password
|
|
</h2>
|
|
</div>
|
|
{!done && isCodeValid !== null && isCodeValid ? (
|
|
<form>
|
|
<div className="form-floating mb-3">
|
|
<input
|
|
type="password"
|
|
className="form-control"
|
|
id="passwordInput"
|
|
placeholder="Password"
|
|
value={password}
|
|
onChange={(e) => setPassword(e.target.value)}
|
|
disabled={isBusy}
|
|
></input>
|
|
<label htmlFor="emailInput" className="form-label">
|
|
Enter new password
|
|
</label>
|
|
</div>
|
|
<div className="form-floating">
|
|
<input
|
|
type="password"
|
|
className="form-control"
|
|
id="confirmPasswordInput"
|
|
placeholder="Confirm Password"
|
|
value={confirmPassword}
|
|
onChange={(e) => setConfirmPassword(e.target.value)}
|
|
disabled={isBusy}
|
|
></input>
|
|
<label
|
|
htmlFor="confirmPasswordInput"
|
|
className="form-label"
|
|
>
|
|
Confirm password
|
|
</label>
|
|
</div>
|
|
<div className="alert-box">
|
|
{"" !== notice && (
|
|
<div className="password-reset-alert" role="alert">
|
|
{notice}
|
|
</div>
|
|
)}
|
|
</div>
|
|
<div className="password-reset-button-wrapper">
|
|
<Button
|
|
className="primary-button"
|
|
onClick={(e) => handleConfirmPasswordReset(e)}
|
|
labelText="Submit"
|
|
disabled={isBusy}
|
|
/>
|
|
</div>
|
|
</form>
|
|
) : null}
|
|
{!done && isCodeValid !== null && !isCodeValid && (
|
|
<div className="success-container">
|
|
<p className="reset-sent-text">
|
|
Bad or already used password reset code.
|
|
</p>
|
|
</div>
|
|
)}
|
|
{done && (
|
|
<div className="success-container">
|
|
<p className="reset-sent-text">Password changed.</p>
|
|
</div>
|
|
)}
|
|
</>
|
|
) : null}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default PasswordResetPage;
|