From e8d03a422d1aa12b4d417304c60407ff3c4298da Mon Sep 17 00:00:00 2001
From: lyzno1 <92089059+lyzno1@users.noreply.github.com>
Date: Thu, 20 Nov 2025 11:19:15 +0800
Subject: [PATCH] fix: improve email code sign-in experience (#28307)
---
.../webapp-signin/check-code/page.tsx | 26 ++++++++++++++++---
web/app/components/base/input/index.tsx | 8 +++---
web/app/signin/check-code/page.tsx | 26 ++++++++++++++++---
.../signin/components/mail-and-code-auth.tsx | 12 ++++++---
4 files changed, 55 insertions(+), 17 deletions(-)
diff --git a/web/app/(shareLayout)/webapp-signin/check-code/page.tsx b/web/app/(shareLayout)/webapp-signin/check-code/page.tsx
index 69131cdabe..00876f97e9 100644
--- a/web/app/(shareLayout)/webapp-signin/check-code/page.tsx
+++ b/web/app/(shareLayout)/webapp-signin/check-code/page.tsx
@@ -1,7 +1,7 @@
'use client'
import { RiArrowLeftLine, RiMailSendFill } from '@remixicon/react'
import { useTranslation } from 'react-i18next'
-import { useCallback, useState } from 'react'
+import { type FormEvent, useCallback, useEffect, useRef, useState } from 'react'
import { useRouter, useSearchParams } from 'next/navigation'
import { useContext } from 'use-context-selector'
import Countdown from '@/app/components/signin/countdown'
@@ -23,6 +23,7 @@ export default function CheckCode() {
const [code, setVerifyCode] = useState('')
const [loading, setIsLoading] = useState(false)
const { locale } = useContext(I18NContext)
+ const codeInputRef = useRef(null)
const redirectUrl = searchParams.get('redirect_url')
const embeddedUserId = useWebAppStore(s => s.embeddedUserId)
@@ -79,6 +80,15 @@ export default function CheckCode() {
}
}
+ const handleSubmit = (event: FormEvent) => {
+ event.preventDefault()
+ verify()
+ }
+
+ useEffect(() => {
+ codeInputRef.current?.focus()
+ }, [])
+
const resendCode = async () => {
try {
const ret = await sendWebAppEMailLoginCode(email, locale)
@@ -107,10 +117,18 @@ export default function CheckCode() {
-
diff --git a/web/app/components/base/input/index.tsx b/web/app/components/base/input/index.tsx
index 688e1dd880..60f80d560b 100644
--- a/web/app/components/base/input/index.tsx
+++ b/web/app/components/base/input/index.tsx
@@ -32,12 +32,11 @@ export type InputProps = {
wrapperClassName?: string
styleCss?: CSSProperties
unit?: string
- ref?: React.Ref
} & Omit, 'size'> & VariantProps
const removeLeadingZeros = (value: string) => value.replace(/^(-?)0+(?=\d)/, '$1')
-const Input = ({
+const Input = React.forwardRef(({
size,
disabled,
destructive,
@@ -53,9 +52,8 @@ const Input = ({
onChange = noop,
onBlur = noop,
unit,
- ref,
...props
-}: InputProps) => {
+}, ref) => {
const { t } = useTranslation()
const handleNumberChange: ChangeEventHandler = (e) => {
if (value === 0) {
@@ -135,7 +133,7 @@ const Input = ({
}
)
-}
+})
Input.displayName = 'Input'
diff --git a/web/app/signin/check-code/page.tsx b/web/app/signin/check-code/page.tsx
index adbde377a1..67e268a761 100644
--- a/web/app/signin/check-code/page.tsx
+++ b/web/app/signin/check-code/page.tsx
@@ -1,7 +1,7 @@
'use client'
import { RiArrowLeftLine, RiMailSendFill } from '@remixicon/react'
import { useTranslation } from 'react-i18next'
-import { useState } from 'react'
+import { type FormEvent, useEffect, useRef, useState } from 'react'
import { useRouter, useSearchParams } from 'next/navigation'
import { useContext } from 'use-context-selector'
import Countdown from '@/app/components/signin/countdown'
@@ -23,6 +23,7 @@ export default function CheckCode() {
const [code, setVerifyCode] = useState('')
const [loading, setIsLoading] = useState(false)
const { locale } = useContext(I18NContext)
+ const codeInputRef = useRef(null)
const verify = async () => {
try {
@@ -58,6 +59,15 @@ export default function CheckCode() {
}
}
+ const handleSubmit = (event: FormEvent) => {
+ event.preventDefault()
+ verify()
+ }
+
+ useEffect(() => {
+ codeInputRef.current?.focus()
+ }, [])
+
const resendCode = async () => {
try {
const ret = await sendEMailLoginCode(email, locale)
@@ -86,10 +96,18 @@ export default function CheckCode() {
-
diff --git a/web/app/signin/components/mail-and-code-auth.tsx b/web/app/signin/components/mail-and-code-auth.tsx
index 35fd5855ca..002aaaf4ad 100644
--- a/web/app/signin/components/mail-and-code-auth.tsx
+++ b/web/app/signin/components/mail-and-code-auth.tsx
@@ -1,4 +1,4 @@
-import { useState } from 'react'
+import { type FormEvent, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useRouter, useSearchParams } from 'next/navigation'
import { useContext } from 'use-context-selector'
@@ -9,7 +9,6 @@ import Toast from '@/app/components/base/toast'
import { sendEMailLoginCode } from '@/service/common'
import { COUNT_DOWN_KEY, COUNT_DOWN_TIME_MS } from '@/app/components/signin/countdown'
import I18NContext from '@/context/i18n'
-import { noop } from 'lodash-es'
type MailAndCodeAuthProps = {
isInvite: boolean
@@ -56,7 +55,12 @@ export default function MailAndCodeAuth({ isInvite }: MailAndCodeAuthProps) {
}
}
- return (