| 
                        123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175 | 
                        - 'use client'
 - import { useCallback, useState } from 'react'
 - import { useTranslation } from 'react-i18next'
 - import useSWR from 'swr'
 - import { useSearchParams } from 'next/navigation'
 - import { basePath } from '@/utils/var'
 - import cn from 'classnames'
 - import { CheckCircleIcon } from '@heroicons/react/24/solid'
 - import Input from '../components/base/input'
 - import Button from '@/app/components/base/button'
 - import { changePasswordWithToken, verifyForgotPasswordToken } from '@/service/common'
 - import Toast from '@/app/components/base/toast'
 - import Loading from '@/app/components/base/loading'
 - import { validPassword } from '@/config'
 - 
 - const ChangePasswordForm = () => {
 -   const { t } = useTranslation()
 -   const searchParams = useSearchParams()
 -   const token = searchParams.get('token')
 - 
 -   const verifyTokenParams = {
 -     url: '/forgot-password/validity',
 -     body: { token },
 -   }
 -   const { data: verifyTokenRes, mutate: revalidateToken } = useSWR(verifyTokenParams, verifyForgotPasswordToken, {
 -     revalidateOnFocus: false,
 -   })
 - 
 -   const [password, setPassword] = useState('')
 -   const [confirmPassword, setConfirmPassword] = useState('')
 -   const [showSuccess, setShowSuccess] = useState(false)
 - 
 -   const showErrorMessage = useCallback((message: string) => {
 -     Toast.notify({
 -       type: 'error',
 -       message,
 -     })
 -   }, [])
 - 
 -   const valid = useCallback(() => {
 -     if (!password.trim()) {
 -       showErrorMessage(t('login.error.passwordEmpty'))
 -       return false
 -     }
 -     if (!validPassword.test(password)) {
 -       showErrorMessage(t('login.error.passwordInvalid'))
 -       return false
 -     }
 -     if (password !== confirmPassword) {
 -       showErrorMessage(t('common.account.notEqual'))
 -       return false
 -     }
 -     return true
 -   }, [password, confirmPassword, showErrorMessage, t])
 - 
 -   const handleChangePassword = useCallback(async () => {
 -     const token = searchParams.get('token') || ''
 - 
 -     if (!valid())
 -       return
 -     try {
 -       await changePasswordWithToken({
 -         url: '/forgot-password/resets',
 -         body: {
 -           token,
 -           new_password: password,
 -           password_confirm: confirmPassword,
 -         },
 -       })
 -       setShowSuccess(true)
 -     }
 -     catch {
 -       await revalidateToken()
 -     }
 -   }, [confirmPassword, password, revalidateToken, searchParams, valid])
 - 
 -   return (
 -     <div className={
 -       cn(
 -         'flex w-full grow flex-col items-center justify-center',
 -         'px-6',
 -         'md:px-[108px]',
 -       )
 -     }>
 -       {!verifyTokenRes && <Loading />}
 -       {verifyTokenRes && !verifyTokenRes.is_valid && (
 -         <div className="flex flex-col md:w-[400px]">
 -           <div className="mx-auto w-full">
 -             <div className="mb-3 flex h-20 w-20 items-center justify-center rounded-[20px] border border-divider-regular bg-components-option-card-option-bg p-5 text-[40px] font-bold shadow-lg">🤷♂️</div>
 -             <h2 className="text-[32px] font-bold text-text-primary">{t('login.invalid')}</h2>
 -           </div>
 -           <div className="mx-auto mt-6 w-full">
 -             <Button variant='primary' className='w-full !text-sm'>
 -               <a href="https://dify.ai">{t('login.explore')}</a>
 -             </Button>
 -           </div>
 -         </div>
 -       )}
 -       {verifyTokenRes && verifyTokenRes.is_valid && !showSuccess && (
 -         <div className='flex flex-col md:w-[400px]'>
 -           <div className="mx-auto w-full">
 -             <h2 className="text-[32px] font-bold text-text-primary">
 -               {t('login.changePassword')}
 -             </h2>
 -             <p className='mt-1 text-sm text-text-secondary'>
 -               {t('login.changePasswordTip')}
 -             </p>
 -           </div>
 - 
 -           <div className="mx-auto mt-6 w-full">
 -             <div className="relative">
 -               {/* Password */}
 -               <div className='mb-5'>
 -                 <label htmlFor="password" className="my-2 flex items-center justify-between text-sm font-medium text-text-primary">
 -                   {t('common.account.newPassword')}
 -                 </label>
 -                 <Input
 -                   id="password"
 -                   type='password'
 -                   value={password}
 -                   onChange={e => setPassword(e.target.value)}
 -                   placeholder={t('login.passwordPlaceholder') || ''}
 -                   className='mt-1'
 -                 />
 -                 <div className='mt-1 text-xs text-text-secondary'>{t('login.error.passwordInvalid')}</div>
 -               </div>
 -               {/* Confirm Password */}
 -               <div className='mb-5'>
 -                 <label htmlFor="confirmPassword" className="my-2 flex items-center justify-between text-sm font-medium text-text-primary">
 -                   {t('common.account.confirmPassword')}
 -                 </label>
 -                 <Input
 -                   id="confirmPassword"
 -                   type='password'
 -                   value={confirmPassword}
 -                   onChange={e => setConfirmPassword(e.target.value)}
 -                   placeholder={t('login.confirmPasswordPlaceholder') || ''}
 -                   className='mt-1'
 -                 />
 -               </div>
 -               <div>
 -                 <Button
 -                   variant='primary'
 -                   className='w-full !text-sm'
 -                   onClick={handleChangePassword}
 -                 >
 -                   {t('common.operation.reset')}
 -                 </Button>
 -               </div>
 -             </div>
 -           </div>
 -         </div>
 -       )}
 -       {verifyTokenRes && verifyTokenRes.is_valid && showSuccess && (
 -         <div className="flex flex-col md:w-[400px]">
 -           <div className="mx-auto w-full">
 -             <div className="mb-3 flex h-20 w-20 items-center justify-center rounded-[20px] border border-divider-regular bg-components-option-card-option-bg p-5 text-[40px] font-bold shadow-lg">
 -               <CheckCircleIcon className='h-10 w-10 text-[#039855]' />
 -             </div>
 -             <h2 className="text-[32px] font-bold text-text-primary">
 -               {t('login.passwordChangedTip')}
 -             </h2>
 -           </div>
 -           <div className="mx-auto mt-6 w-full">
 -             <Button variant='primary' className='w-full'>
 -               <a href={`${basePath}/signin`}>{t('login.passwordChanged')}</a>
 -             </Button>
 -           </div>
 -         </div>
 -       )}
 -     </div>
 -   )
 - }
 - 
 - export default ChangePasswordForm
 
 
  |