mirror of
				https://github.com/langgenius/dify.git
				synced 2025-10-31 02:42:59 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			173 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			173 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| 'use client'
 | |
| import React, { useEffect } from 'react'
 | |
| import { useTranslation } from 'react-i18next'
 | |
| 
 | |
| import Link from 'next/link'
 | |
| import { useRouter } from 'next/navigation'
 | |
| 
 | |
| import type { SubmitHandler } from 'react-hook-form'
 | |
| import { useForm } from 'react-hook-form'
 | |
| import { z } from 'zod'
 | |
| import { zodResolver } from '@hookform/resolvers/zod'
 | |
| import Loading from '../components/base/loading'
 | |
| import classNames from '@/utils/classnames'
 | |
| import Button from '@/app/components/base/button'
 | |
| 
 | |
| import { fetchInitValidateStatus, fetchSetupStatus, setup } from '@/service/common'
 | |
| import type { InitValidateStatusResponse, SetupStatusResponse } from '@/models/common'
 | |
| 
 | |
| const validPassword = /^(?=.*[a-zA-Z])(?=.*\d).{8,}$/
 | |
| 
 | |
| const accountFormSchema = z.object({
 | |
|   email: z
 | |
|     .string()
 | |
|     .min(1, { message: 'login.error.emailInValid' })
 | |
|     .email('login.error.emailInValid'),
 | |
|   name: z.string().min(1, { message: 'login.error.nameEmpty' }),
 | |
|   password: z.string().min(8, {
 | |
|     message: 'login.error.passwordLengthInValid',
 | |
|   }).regex(validPassword, 'login.error.passwordInvalid'),
 | |
| })
 | |
| 
 | |
| type AccountFormValues = z.infer<typeof accountFormSchema>
 | |
| 
 | |
| const InstallForm = () => {
 | |
|   const { t } = useTranslation()
 | |
|   const router = useRouter()
 | |
|   const [showPassword, setShowPassword] = React.useState(false)
 | |
|   const [loading, setLoading] = React.useState(true)
 | |
|   const {
 | |
|     register,
 | |
|     handleSubmit,
 | |
|     formState: { errors },
 | |
|   } = useForm<AccountFormValues>({
 | |
|     resolver: zodResolver(accountFormSchema),
 | |
|     defaultValues: {
 | |
|       name: '',
 | |
|       password: '',
 | |
|       email: '',
 | |
|     },
 | |
|   })
 | |
| 
 | |
|   const onSubmit: SubmitHandler<AccountFormValues> = async (data) => {
 | |
|     await setup({
 | |
|       body: {
 | |
|         ...data,
 | |
|       },
 | |
|     })
 | |
|     router.push('/signin')
 | |
|   }
 | |
| 
 | |
|   const handleSetting = async () => {
 | |
|     handleSubmit(onSubmit)()
 | |
|   }
 | |
| 
 | |
|   useEffect(() => {
 | |
|     fetchSetupStatus().then((res: SetupStatusResponse) => {
 | |
|       if (res.step === 'finished') {
 | |
|         localStorage.setItem('setup_status', 'finished')
 | |
|         window.location.href = '/signin'
 | |
|       }
 | |
|       else {
 | |
|         fetchInitValidateStatus().then((res: InitValidateStatusResponse) => {
 | |
|           if (res.status === 'not_started')
 | |
|             window.location.href = '/init'
 | |
|         })
 | |
|       }
 | |
|       setLoading(false)
 | |
|     })
 | |
|   }, [])
 | |
| 
 | |
|   return (
 | |
|     loading
 | |
|       ? <Loading />
 | |
|       : <>
 | |
|         <div className="sm:mx-auto sm:w-full sm:max-w-md">
 | |
|           <h2 className="text-[32px] font-bold text-gray-900">{t('login.setAdminAccount')}</h2>
 | |
|           <p className='
 | |
|           mt-1 text-sm text-gray-600
 | |
|         '>{t('login.setAdminAccountDesc')}</p>
 | |
|         </div>
 | |
|         <div className="grow mt-8 sm:mx-auto sm:w-full sm:max-w-md">
 | |
|           <div className="bg-white ">
 | |
|             <form onSubmit={handleSubmit(onSubmit)}>
 | |
|               <div className='mb-5'>
 | |
|                 <label htmlFor="email" className="my-2 flex items-center justify-between text-sm font-medium text-gray-900">
 | |
|                   {t('login.email')}
 | |
|                 </label>
 | |
|                 <div className="mt-1">
 | |
|                   <input
 | |
|                     {...register('email')}
 | |
|                     placeholder={t('login.emailPlaceholder') || ''}
 | |
|                     className={'appearance-none block w-full rounded-lg pl-[14px] px-3 py-2 border border-gray-200 hover:border-gray-300 hover:shadow-sm focus:outline-none focus:ring-primary-500 focus:border-primary-500 placeholder-gray-400 caret-primary-600 sm:text-sm'}
 | |
|                   />
 | |
|                   {errors.email && <span className='text-red-400 text-sm'>{t(`${errors.email?.message}`)}</span>}
 | |
|                 </div>
 | |
| 
 | |
|               </div>
 | |
| 
 | |
|               <div className='mb-5'>
 | |
|                 <label htmlFor="name" className="my-2 flex items-center justify-between text-sm font-medium text-gray-900">
 | |
|                   {t('login.name')}
 | |
|                 </label>
 | |
|                 <div className="mt-1 relative rounded-md shadow-sm">
 | |
|                   <input
 | |
|                     {...register('name')}
 | |
|                     placeholder={t('login.namePlaceholder') || ''}
 | |
|                     className={'appearance-none block w-full rounded-lg pl-[14px] px-3 py-2 border border-gray-200 hover:border-gray-300 hover:shadow-sm focus:outline-none focus:ring-primary-500 focus:border-primary-500 placeholder-gray-400 caret-primary-600 sm:text-sm pr-10'}
 | |
|                   />
 | |
|                 </div>
 | |
|                 {errors.name && <span className='text-red-400 text-sm'>{t(`${errors.name.message}`)}</span>}
 | |
|               </div>
 | |
| 
 | |
|               <div className='mb-5'>
 | |
|                 <label htmlFor="password" className="my-2 flex items-center justify-between text-sm font-medium text-gray-900">
 | |
|                   {t('login.password')}
 | |
|                 </label>
 | |
|                 <div className="mt-1 relative rounded-md shadow-sm">
 | |
|                   <input
 | |
|                     {...register('password')}
 | |
|                     type={showPassword ? 'text' : 'password'}
 | |
|                     placeholder={t('login.passwordPlaceholder') || ''}
 | |
|                     className={'appearance-none block w-full rounded-lg pl-[14px] px-3 py-2 border border-gray-200 hover:border-gray-300 hover:shadow-sm focus:outline-none focus:ring-primary-500 focus:border-primary-500 placeholder-gray-400 caret-primary-600 sm:text-sm pr-10'}
 | |
|                   />
 | |
| 
 | |
|                   <div className="absolute inset-y-0 right-0 flex items-center pr-3">
 | |
|                     <button
 | |
|                       type="button"
 | |
|                       onClick={() => setShowPassword(!showPassword)}
 | |
|                       className="text-gray-400 hover:text-gray-500 focus:outline-none focus:text-gray-500"
 | |
|                     >
 | |
|                       {showPassword ? '👀' : '😝'}
 | |
|                     </button>
 | |
|                   </div>
 | |
|                 </div>
 | |
| 
 | |
|                 <div className={classNames('mt-1 text-xs text-gray-500', {
 | |
|                   'text-red-400 !text-sm': errors.password,
 | |
|                 })}>{t('login.error.passwordInvalid')}</div>
 | |
|               </div>
 | |
| 
 | |
|               <div>
 | |
|                 <Button variant='primary' className='w-full' onClick={handleSetting}>
 | |
|                   {t('login.installBtn')}
 | |
|                 </Button>
 | |
|               </div>
 | |
|             </form>
 | |
|             <div className="block w-full mt-2 text-xs text-gray-600">
 | |
|               {t('login.license.tip')}
 | |
|                
 | |
|               <Link
 | |
|                 className='text-primary-600'
 | |
|                 target='_blank' rel='noopener noreferrer'
 | |
|                 href={'https://docs.dify.ai/user-agreement/open-source'}
 | |
|               >{t('login.license.link')}</Link>
 | |
|             </div>
 | |
|           </div>
 | |
|         </div>
 | |
|       </>
 | |
|   )
 | |
| }
 | |
| 
 | |
| export default InstallForm
 | 
