'use client' import type { InitValidateStatusResponse, SetupStatusResponse } from '@/models/common' import { useStore } from '@tanstack/react-form' import Link from 'next/link' import { useRouter } from 'next/navigation' import * as React from 'react' import { useEffect } from 'react' import { useTranslation } from 'react-i18next' import { z } from 'zod' import Button from '@/app/components/base/button' import { formContext, useAppForm } from '@/app/components/base/form' import { zodSubmitValidator } from '@/app/components/base/form/utils/zod-submit-validator' import Input from '@/app/components/base/input' import { validPassword } from '@/config' import { useDocLink } from '@/context/i18n' import useDocumentTitle from '@/hooks/use-document-title' import { fetchInitValidateStatus, fetchSetupStatus, login, setup } from '@/service/common' import { cn } from '@/utils/classnames' import { encryptPassword as encodePassword } from '@/utils/encryption' import Loading from '../components/base/loading' const accountFormSchema = z.object({ email: z .string() .min(1, { message: 'error.emailInValid' }) .email('error.emailInValid'), name: z.string().min(1, { message: 'error.nameEmpty' }), password: z.string().min(8, { message: 'error.passwordLengthInValid', }).regex(validPassword, 'error.passwordInvalid'), }) const InstallForm = () => { useDocumentTitle('') const { t, i18n } = useTranslation() const docLink = useDocLink() const router = useRouter() const [showPassword, setShowPassword] = React.useState(false) const [loading, setLoading] = React.useState(true) const form = useAppForm({ defaultValues: { name: '', password: '', email: '', }, validators: { onSubmit: zodSubmitValidator(accountFormSchema), }, onSubmit: async ({ value }) => { // First, setup the admin account await setup({ body: { ...value, language: i18n.language, }, }) // Then, automatically login with the same credentials const loginRes = await login({ url: '/login', body: { email: value.email, password: encodePassword(value.password), }, }) // Store tokens and redirect to apps if login successful if (loginRes.result === 'success') { router.replace('/apps') } else { // Fallback to signin page if auto-login fails router.replace('/signin') } }, }) const isSubmitting = useStore(form.store, state => state.isSubmitting) const emailErrors = useStore(form.store, state => state.fieldMeta.email?.errors) const nameErrors = useStore(form.store, state => state.fieldMeta.name?.errors) const passwordErrors = useStore(form.store, state => state.fieldMeta.password?.errors) useEffect(() => { fetchSetupStatus().then((res: SetupStatusResponse) => { if (res.step === 'finished') { localStorage.setItem('setup_status', 'finished') router.push('/signin') } else { fetchInitValidateStatus().then((res: InitValidateStatusResponse) => { if (res.status === 'not_started') router.push('/init') }) } setLoading(false) }) }, []) return ( loading ? : ( <>

{t('setAdminAccount', { ns: 'login' })}

{t('setAdminAccountDesc', { ns: 'login' })}

{ e.preventDefault() e.stopPropagation() if (isSubmitting) return form.handleSubmit() }} >
{field => ( field.handleChange(e.target.value)} onBlur={field.handleBlur} placeholder={t('emailPlaceholder', { ns: 'login' }) || ''} /> )} {emailErrors && emailErrors.length > 0 && ( {t(`${emailErrors[0]}` as 'error.emailInValid', { ns: 'login' })} )}
{field => ( field.handleChange(e.target.value)} onBlur={field.handleBlur} placeholder={t('namePlaceholder', { ns: 'login' }) || ''} /> )}
{nameErrors && nameErrors.length > 0 && ( {t(`${nameErrors[0]}` as 'error.nameEmpty', { ns: 'login' })} )}
{field => ( field.handleChange(e.target.value)} onBlur={field.handleBlur} placeholder={t('passwordPlaceholder', { ns: 'login' }) || ''} /> )}
0, })} > {t('error.passwordInvalid', { ns: 'login' })}
{t('license.tip', { ns: 'login' })}   {t('license.link', { ns: 'login' })}
) ) } export default InstallForm