'use client' import type { MailRegisterResponse } from '@/service/use-common' import { Button } from '@langgenius/dify-ui/button' import { cn } from '@langgenius/dify-ui/cn' import { toast } from '@langgenius/dify-ui/toast' import { useQueryClient } from '@tanstack/react-query' import Cookies from 'js-cookie' import { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' import { rememberRegistrationSuccess } from '@/app/components/base/amplitude/registration-tracking' import Input from '@/app/components/base/input' import { resolvePostLoginRedirect } from '@/app/signin/utils/post-login-redirect' import { validPassword } from '@/config' import { useLocale } from '@/context/i18n' import { useRouter, useSearchParams } from '@/next/navigation' import { consoleQuery } from '@/service/client' import { useMailRegister } from '@/service/use-common' import { rememberCreateAppExternalAttribution } from '@/utils/create-app-tracking' import { sendGAEvent } from '@/utils/gtag' import { replaceLoginRedirect } from '@/utils/login-redirect.client' import { getBrowserTimezone } from '@/utils/timezone' import { basePath } from '@/utils/var' const parseUtmInfo = () => { const utmInfoStr = Cookies.get('utm_info') if (!utmInfoStr) return null try { return JSON.parse(utmInfoStr) } catch (e) { console.error('Failed to parse utm_info cookie:', e) return null } } const ChangePasswordForm = () => { const { t } = useTranslation() const router = useRouter() const queryClient = useQueryClient() const searchParams = useSearchParams() const token = decodeURIComponent(searchParams.get('token') || '') const locale = useLocale() const [password, setPassword] = useState('') const [confirmPassword, setConfirmPassword] = useState('') const { mutateAsync: register, isPending } = useMailRegister() const showErrorMessage = useCallback((message: string) => { toast.error(message) }, []) const valid = useCallback(() => { if (!password.trim()) { showErrorMessage(t(($) => $['error.passwordEmpty'], { ns: 'login' })) return false } if (!validPassword.test(password)) { showErrorMessage(t(($) => $['error.passwordInvalid'], { ns: 'login' })) return false } if (password !== confirmPassword) { showErrorMessage(t(($) => $['account.notEqual'], { ns: 'common' })) return false } return true }, [password, confirmPassword, showErrorMessage, t]) const handleSubmit = useCallback(async () => { if (!valid()) return try { const res = await register({ token, new_password: password, password_confirm: confirmPassword, language: locale, timezone: getBrowserTimezone(), }) const { result } = res as MailRegisterResponse if (result === 'success') { const utmInfo = parseUtmInfo() rememberCreateAppExternalAttribution({ utmInfo }) // Defer the Amplitude event until the user ID is attached. The app context // external sync replays it after setUserId runs once the redirect lands on /apps. // Firing it here would record it under an anonymous Amplitude profile. rememberRegistrationSuccess({ method: 'email', utmInfo }) sendGAEvent(utmInfo ? 'user_registration_success_with_utm' : 'user_registration_success', { method: 'email', ...utmInfo, }) Cookies.remove('utm_info') // Clean up: remove utm_info cookie toast.success(t(($) => $['api.actionSuccess'], { ns: 'common' })) await queryClient.resetQueries({ queryKey: consoleQuery.account.profile.get.key() }) replaceLoginRedirect(resolvePostLoginRedirect(searchParams), router.replace, basePath) } } catch (error) { console.error(error) } }, [ password, token, valid, confirmPassword, register, locale, queryClient, router, searchParams, t, ]) return (

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

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

{/* Password */}
setPassword(e.target.value)} placeholder={t(($) => $.passwordPlaceholder, { ns: 'login' }) || ''} />
{t(($) => $['error.passwordInvalid'], { ns: 'login' })}
{/* Confirm Password */}
setConfirmPassword(e.target.value)} placeholder={t(($) => $.confirmPasswordPlaceholder, { ns: 'login' }) || ''} />
) } export default ChangePasswordForm