'use client' import type { FormActions } from '@langgenius/dify-ui/form' import { Button, buttonVariants } from '@langgenius/dify-ui/button' import { cn } from '@langgenius/dify-ui/cn' import { Field, FieldDescription, FieldError, FieldLabel, FieldValidity, } from '@langgenius/dify-ui/field' import { Form } from '@langgenius/dify-ui/form' import { Input } from '@langgenius/dify-ui/input' import { useCallback, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import Loading from '@/app/components/base/loading' import { validPassword } from '@/config' import useDocumentTitle from '@/hooks/use-document-title' import { useSearchParams } from '@/next/navigation' import { changePasswordWithToken } from '@/service/common' import { useVerifyForgotPasswordToken } from '@/service/use-common' import { basePath } from '@/utils/var' type PasswordFormValues = { password: string confirmPassword: string } const ChangePasswordForm = () => { const { t } = useTranslation() const searchParams = useSearchParams() const token = searchParams.get('token') const isTokenMissing = !token const { data: verifyTokenRes, refetch: revalidateToken } = useVerifyForgotPasswordToken(token) const formActionsRef = useRef(null) const confirmPasswordRef = useRef(null) const [isSubmitting, setIsSubmitting] = useState(false) const [showSuccess, setShowSuccess] = useState(false) const isVerifyingToken = !isTokenMissing && !verifyTokenRes const isTokenInvalid = isTokenMissing || (verifyTokenRes && !verifyTokenRes.is_valid) const documentTitle = isVerifyingToken ? t(($) => $.loading, { ns: 'common' }) : isTokenInvalid ? t(($) => $.invalid, { ns: 'login' }) : showSuccess ? t(($) => $.passwordChangedTip, { ns: 'login' }) : t(($) => $.changePassword, { ns: 'login' }) useDocumentTitle(documentTitle) const handleChangePassword = useCallback( async (formValues: PasswordFormValues) => { if (isSubmitting) return const resetToken = verifyTokenRes?.token ?? '' setIsSubmitting(true) try { await changePasswordWithToken({ url: '/forgot-password/resets', body: { token: resetToken, new_password: formValues.password, password_confirm: formValues.confirmPassword, }, }) setShowSuccess(true) } catch { await revalidateToken() } finally { setIsSubmitting(false) } }, [isSubmitting, revalidateToken, verifyTokenRes?.token], ) return (
{isVerifyingToken && } {isTokenInvalid && (
🤷‍♂️

{t(($) => $.invalid, { ns: 'login' })}

)} {verifyTokenRes && verifyTokenRes.is_valid && !showSuccess && (

{t(($) => $.changePassword, { ns: 'login' })}

{t(($) => $.changePasswordTip, { ns: 'login' })}

actionsRef={formActionsRef} className="relative" onFormSubmit={(formValues) => { void handleChangePassword(formValues) }} > { const passwordValue = String(value) if (!passwordValue.trim()) return t(($) => $['error.passwordEmpty'], { ns: 'login' }) return validPassword.test(passwordValue) ? null : t(($) => $['error.passwordInvalid'], { ns: 'login' }) }} className="mb-5" > {t(($) => $['account.newPassword'], { ns: 'common' })} { if (confirmPasswordRef.current?.value) formActionsRef.current?.validate('confirmPassword') }} placeholder={t(($) => $.passwordPlaceholder, { ns: 'login' }) || ''} /> {({ validity }) => validity.valid !== false ? ( {t(($) => $['error.passwordInvalid'], { ns: 'login' })} ) : null } {({ validity }) => ( {t( ($) => $[ validity.valueMissing ? 'error.passwordEmpty' : 'error.passwordInvalid' ], { ns: 'login' }, )} )} { const confirmationValue = String(value) return !confirmationValue || confirmationValue === formValues.password ? null : t(($) => $['account.notEqual'], { ns: 'common' }) }} className="mb-5" > {t(($) => $['account.confirmPassword'], { ns: 'common' })} $.confirmPasswordPlaceholder, { ns: 'login' }) || ''} /> {t(($) => $['account.notEqual'], { ns: 'common' })}
)} {verifyTokenRes && verifyTokenRes.is_valid && showSuccess && (

{t(($) => $.passwordChangedTip, { ns: 'login' })}

)}
) } export default ChangePasswordForm