import { createSignal, createEffect, Show } from "solid-js"; import { A, useNavigate, useSearchParams } from "@solidjs/router"; import { Title, Meta } from "@solidjs/meta"; import CountdownCircleTimer from "~/components/CountdownCircleTimer"; import Eye from "~/components/icons/Eye"; import EyeSlash from "~/components/icons/EyeSlash"; import { validatePassword } from "~/lib/validation"; import { api } from "~/lib/api"; export default function PasswordResetPage() { const navigate = useNavigate(); const [searchParams] = useSearchParams(); const [passwordBlurred, setPasswordBlurred] = createSignal(false); const [passwordChangeLoading, setPasswordChangeLoading] = createSignal(false); const [passwordsMatch, setPasswordsMatch] = createSignal(false); const [showPasswordLengthWarning, setShowPasswordLengthWarning] = createSignal(false); const [passwordLengthSufficient, setPasswordLengthSufficient] = createSignal(false); const [showRequestNewEmail, setShowRequestNewEmail] = createSignal(false); const [countDown, setCountDown] = createSignal(false); const [error, setError] = createSignal(""); const [showPasswordInput, setShowPasswordInput] = createSignal(false); const [showPasswordConfInput, setShowPasswordConfInput] = createSignal(false); let newPasswordRef: HTMLInputElement | undefined; let newPasswordConfRef: HTMLInputElement | undefined; // Get token from URL const token = searchParams.token; createEffect(() => { if (!token) { navigate("/login/request-password-reset"); } }); const setNewPasswordTrigger = async (e: Event) => { e.preventDefault(); setShowRequestNewEmail(false); setError(""); if (!newPasswordRef || !newPasswordConfRef) { setError("Please fill in all fields"); return; } const newPassword = newPasswordRef.value; const newPasswordConf = newPasswordConfRef.value; // Validate password const passwordValidation = validatePassword(newPassword); if (!passwordValidation.isValid) { setError(passwordValidation.errors[0] || "Invalid password"); return; } if (newPassword !== newPasswordConf) { setError("Passwords do not match"); return; } setPasswordChangeLoading(true); try { const result = await api.auth.resetPassword.mutate({ token: token, newPassword, newPasswordConfirmation: newPasswordConf }); if (result.success) { setCountDown(true); } else { setError("Failed to reset password"); } } catch (err: any) { console.error("Password reset error:", err); const errorMsg = err.message || "An error occurred. Please try again."; if (errorMsg.includes("expired") || errorMsg.includes("token")) { setShowRequestNewEmail(true); setError("Token has expired"); } else { setError(errorMsg); } } finally { setPasswordChangeLoading(false); } }; const checkForMatch = (newPassword: string, newPasswordConf: string) => { if (newPassword === newPasswordConf) { setPasswordsMatch(true); } else { setPasswordsMatch(false); } }; const checkPasswordLength = (password: string) => { if (password.length >= 8) { setPasswordLengthSufficient(true); setShowPasswordLengthWarning(false); } else { setPasswordLengthSufficient(false); if (passwordBlurred()) { setShowPasswordLengthWarning(true); } } }; const passwordLengthBlurCheck = () => { if ( !passwordLengthSufficient() && newPasswordRef && newPasswordRef.value !== "" ) { setShowPasswordLengthWarning(true); } setPasswordBlurred(true); }; const handleNewPasswordChange = (e: Event) => { const target = e.target as HTMLInputElement; checkPasswordLength(target.value); if (newPasswordConfRef) { checkForMatch(target.value, newPasswordConfRef.value); } }; const handlePasswordConfChange = (e: Event) => { const target = e.target as HTMLInputElement; if (newPasswordRef) { checkForMatch(newPasswordRef.value, target.value); } }; const handlePasswordBlur = () => { passwordLengthBlurCheck(); }; // Render countdown timer const renderTime = (timeRemaining: number) => { if (timeRemaining === 0) { navigate("/login"); } return (