148 lines
5.1 KiB
TypeScript
148 lines
5.1 KiB
TypeScript
import { type FormEvent, useEffect, useRef, useState } from 'react'
|
|
import { Link } from 'react-router-dom'
|
|
import { requestForgotPassword } from '../api/passwordFlow'
|
|
|
|
/** Mirrors CodeIgniter `user/forgot_password.php` + confirmation modal from `password_reset_confirmation.php`. */
|
|
export function ForgotPasswordPage() {
|
|
const [email, setEmail] = useState('')
|
|
const [error, setError] = useState<string | null>(null)
|
|
const [loading, setLoading] = useState(false)
|
|
const [confirmEmail, setConfirmEmail] = useState<string | null>(null)
|
|
const confirmModalRef = useRef<HTMLDivElement | null>(null)
|
|
|
|
useEffect(() => {
|
|
if (!confirmEmail) return
|
|
const el = confirmModalRef.current
|
|
const B = (
|
|
window as unknown as {
|
|
bootstrap?: { Modal: { getOrCreateInstance: (n: HTMLElement) => { show: () => void } } }
|
|
}
|
|
).bootstrap
|
|
if (el && B?.Modal?.getOrCreateInstance) {
|
|
B.Modal.getOrCreateInstance(el).show()
|
|
}
|
|
}, [confirmEmail])
|
|
|
|
async function onSubmit(e: FormEvent) {
|
|
e.preventDefault()
|
|
setLoading(true)
|
|
setError(null)
|
|
try {
|
|
await requestForgotPassword(email)
|
|
setConfirmEmail(email.trim())
|
|
} catch (err) {
|
|
setError(err instanceof Error ? err.message : 'Request failed.')
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="ci-auth-bg flex-grow-1 py-4">
|
|
<div className="registration-form ci-parity container mt-5 mb-5">
|
|
<form
|
|
className="text-start mx-auto"
|
|
style={{ maxWidth: 600 }}
|
|
onSubmit={(e) => void onSubmit(e)}
|
|
noValidate
|
|
>
|
|
<div className="text-center mb-4">
|
|
<Link to="/">
|
|
<img
|
|
src="/alrahma_logo.png"
|
|
alt=""
|
|
style={{ width: 180, height: 120, objectFit: 'contain' }}
|
|
onError={(ev) => {
|
|
;(ev.target as HTMLImageElement).style.display = 'none'
|
|
}}
|
|
/>
|
|
</Link>
|
|
</div>
|
|
|
|
<h3 className="text-center text-success mb-4" style={{ fontFamily: 'Arial, sans-serif' }}>
|
|
Reset Your Password
|
|
</h3>
|
|
|
|
<div className="centered-paragraph mb-4 text-center text-muted">
|
|
<p className="mb-1">Please enter the email address you used to register with us.</p>
|
|
<p className="mb-0">We'll send you a link to reset your password.</p>
|
|
</div>
|
|
|
|
{error ? (
|
|
<div className="alert alert-danger text-center" role="alert">
|
|
{error}
|
|
</div>
|
|
) : null}
|
|
|
|
<div className="form-group mb-3">
|
|
<label className="form-label visually-hidden" htmlFor="forgot-email">
|
|
Email
|
|
</label>
|
|
<input
|
|
type="email"
|
|
className="form-control item"
|
|
id="forgot-email"
|
|
name="email"
|
|
maxLength={50}
|
|
placeholder="Email Address"
|
|
required
|
|
value={email}
|
|
onChange={(e) => setEmail(e.target.value)}
|
|
autoComplete="email"
|
|
/>
|
|
</div>
|
|
|
|
<div className="d-grid mb-3">
|
|
<button type="submit" className="btn btn-success item" disabled={loading}>
|
|
{loading ? 'Sending…' : 'Reset Password'}
|
|
</button>
|
|
</div>
|
|
|
|
<div className="text-center">
|
|
<p className="mb-0">Don't have an account?</p>
|
|
<Link className="d-inline-block mt-1" to="/register">
|
|
Register now
|
|
</Link>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<div
|
|
className="modal fade"
|
|
id="emailConfirmModal"
|
|
tabIndex={-1}
|
|
ref={confirmModalRef}
|
|
aria-labelledby="emailConfirmLabel"
|
|
aria-hidden="true"
|
|
>
|
|
<div className="modal-dialog modal-dialog-centered modal-lg">
|
|
<div className="modal-content rounded-4 shadow border-0" style={{ maxWidth: 600, margin: 'auto' }}>
|
|
<div className="modal-body text-center">
|
|
<img
|
|
src="/alrahma_logo.png"
|
|
alt=""
|
|
style={{ width: 180, height: 120, objectFit: 'contain' }}
|
|
onError={(ev) => {
|
|
;(ev.target as HTMLImageElement).style.display = 'none'
|
|
}}
|
|
/>
|
|
<h5 className="modal-title text-success" id="emailConfirmLabel">
|
|
Check Your Email
|
|
</h5>
|
|
<p className="lead mt-3 mb-2">
|
|
A link to reset the password has been sent to this email:
|
|
<br />
|
|
<strong>{confirmEmail ?? ''}</strong>
|
|
</p>
|
|
<p className="mb-0">Please check your inbox and follow the instructions to reset the password.</p>
|
|
<Link className="btn btn-success mt-3" to="/login">
|
|
Return to Login
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|