/
opt
/
canhelp
/
apps
/
web
/
src
/
app
/
(auth)
/
reset-password
/
/opt/canhelp/apps/web/src/app/(auth)/reset-password
mkdir
upload
Name
Size
Mode
Actions
page.tsx
4449
0644
edit
dl
rm
Edit:
/opt/canhelp/apps/web/src/app/(auth)/reset-password/page.tsx
(4449B)
'use client' import { useState, useEffect, Suspense } from 'react' import { useRouter, useSearchParams } from 'next/navigation' import Link from 'next/link' import { authClient } from '@/lib/auth' import { useLocale } from '@/context/locale' function ResetPasswordForm() { const router = useRouter() const searchParams = useSearchParams() const { t } = useLocale() const [loading, setLoading] = useState(false) const [error, setError] = useState('') const token = searchParams.get('token') useEffect(() => { if (!token) { setError(t('reset.error.invalid')) } }, [token, t]) async function handleSubmit(e: React.FormEvent<HTMLFormElement>) { e.preventDefault() setError('') const form = new FormData(e.currentTarget) const newPassword = form.get('password') as string const confirm = form.get('confirm') as string if (newPassword !== confirm) { setError(t('reset.error.mismatch')) return } if (!token) { setError(t('reset.error.invalid')) return } setLoading(true) let result: any = null try { result = await authClient.resetPassword({ newPassword, token }) } catch { setError(t('reset.error.invalid')) setLoading(false) return } if (result?.error) { setError(result.error.message ?? t('reset.error.invalid')) setLoading(false) } else { // Show success briefly then redirect setError('') setTimeout(() => router.push('/login'), 2000) } } return ( <div className="min-h-screen flex items-center justify-center px-4"> <div className="w-full max-w-md"> <div className="text-center mb-8"> <h1 className="text-3xl font-bold text-white">{t('reset.title')}</h1> <p className="text-white/70 mt-2">{t('reset.subtitle')}</p> </div> <form onSubmit={handleSubmit} className="bg-white rounded-xl border border-gray-200 p-6 space-y-4"> {error && ( <div className="bg-red-50 text-red-700 p-3 rounded-lg text-sm"> {error} {!token && ( <span> {' '} <Link href="/forgot-password" className="underline font-medium"> {t('reset.back_to_login').replace('sign in', 'request new link')} </Link> </span> )} </div> )} {loading && !error && ( <div className="bg-green-50 text-green-700 p-3 rounded-lg text-sm"> {t('reset.success')} </div> )} <div> <label className="block text-sm font-medium text-gray-700 mb-1">{t('reset.password')}</label> <input name="password" type="password" required minLength={8} autoComplete="new-password" disabled={!token || loading} className="w-full border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-400 disabled:opacity-50" /> </div> <div> <label className="block text-sm font-medium text-gray-700 mb-1">{t('reset.confirm')}</label> <input name="confirm" type="password" required minLength={8} autoComplete="new-password" disabled={!token || loading} className="w-full border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-400 disabled:opacity-50" /> </div> <button type="submit" disabled={!token || loading} className="w-full bg-green-600 text-white py-3 rounded-xl font-semibold hover:bg-green-700 disabled:opacity-50" > {loading ? t('reset.submitting') : t('reset.submit')} </button> <p className="text-center text-sm text-gray-500"> <Link href="/login" className="text-green-600 hover:underline font-medium"> {t('reset.back_to_login')} </Link> </p> </form> </div> </div> ) } export default function ResetPasswordPage() { return ( <Suspense fallback={<div className="min-h-screen flex items-center justify-center"><p>Loading...</p></div>}> <ResetPasswordForm /> </Suspense> ) }
Save
cmd:
run