Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
F
frontend-data-crawler-be
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
BangNSK
frontend-data-crawler-be
Commits
b8e34e6e
Commit
b8e34e6e
authored
Jul 29, 2026
by
BangNSK
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: keep verification resend action visible
parent
673afd42
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
41 additions
and
16 deletions
+41
-16
Login.tsx
src/pages/Login.tsx
+37
-16
feedback-regression.test.mjs
tests/feedback-regression.test.mjs
+4
-0
No files found.
src/pages/Login.tsx
View file @
b8e34e6e
...
...
@@ -11,15 +11,15 @@ export const Login: React.FC = () => {
const
[
password
,
setPassword
]
=
useState
(
''
);
const
[
error
,
setError
]
=
useState
(
''
);
const
[
submitting
,
setSubmitting
]
=
useState
(
false
);
const
[
canResendVerification
,
setCanResendVerification
]
=
useState
(
false
);
const
[
resending
,
setResending
]
=
useState
(
false
);
const
[
resendMessage
,
setResendMessage
]
=
useState
(
''
);
const
[
resendStatus
,
setResendStatus
]
=
useState
<
'success'
|
'error'
|
null
>
(
null
);
const
handleSubmit
=
async
(
e
:
React
.
FormEvent
)
=>
{
e
.
preventDefault
();
setError
(
''
);
setResendMessage
(
''
);
set
CanResendVerification
(
false
);
set
ResendStatus
(
null
);
setSubmitting
(
true
);
try
{
await
login
(
email
,
password
);
...
...
@@ -27,9 +27,11 @@ export const Login: React.FC = () => {
}
catch
(
err
:
any
)
{
console
.
error
(
err
);
const
code
=
err
.
response
?.
data
?.
code
;
setCanResendVerification
(
code
===
'USER_INACTIVE'
)
;
const
isInactiveAccount
=
code
===
'USER_INACTIVE'
||
err
.
response
?.
status
===
403
;
setError
(
code
===
'INVALID_CREDENTIALS'
isInactiveAccount
?
'Tài khoản chưa được xác thực hoặc đã bị khóa. Bạn có thể gửi lại email xác thực bên dưới.'
:
code
===
'INVALID_CREDENTIALS'
?
'Tài khoản hoặc mật khẩu không chính xác.'
:
err
.
response
?.
data
?.
message
||
'Đăng nhập thất bại. Vui lòng kiểm tra lại thông tin.'
,
);
...
...
@@ -39,14 +41,23 @@ export const Login: React.FC = () => {
};
const
handleResendVerification
=
async
()
=>
{
if
(
!
email
.
trim
())
{
setResendStatus
(
'error'
);
setResendMessage
(
'Vui lòng nhập địa chỉ email trước khi gửi lại email xác thực.'
);
return
;
}
setResending
(
true
);
setResendMessage
(
''
);
setResendStatus
(
null
);
try
{
const
response
=
await
api
.
post
(
'/auth/resend-verification'
,
{
email
});
setResendStatus
(
'success'
);
setResendMessage
(
response
.
data
.
message
||
'Nếu tài khoản chưa được xác thực, email xác thực đã được gửi lại.'
,
);
}
catch
(
err
:
any
)
{
setResendStatus
(
'error'
);
setResendMessage
(
err
.
response
?.
data
?.
message
||
'Không thể gửi lại email xác thực. Vui lòng thử lại sau.'
);
}
finally
{
setResending
(
false
);
...
...
@@ -71,21 +82,18 @@ export const Login: React.FC = () => {
{
error
&&
(
<
div
className=
"rounded-lg bg-rose-50 p-4 text-sm text-rose-700 border border-rose-100"
role=
"alert"
>
<
p
>
{
error
}
</
p
>
{
canResendVerification
&&
(
<
button
type=
"button"
onClick=
{
()
=>
void
handleResendVerification
()
}
disabled=
{
resending
}
className=
"mt-3 inline-flex min-h-11 items-center font-semibold text-indigo-700 hover:text-indigo-900 disabled:opacity-60"
>
{
resending
&&
<
Loader2
className=
"mr-2 h-4 w-4 animate-spin"
/>
}
Gửi lại email xác thực
</
button
>
)
}
</
div
>
)
}
{
resendMessage
&&
(
<
div
className=
"rounded-lg border border-emerald-100 bg-emerald-50 p-4 text-sm text-emerald-700"
aria
-
live=
"polite"
>
<
div
className=
{
`rounded-lg border p-4 text-sm ${
resendStatus === 'error'
? 'border-rose-100 bg-rose-50 text-rose-700'
: 'border-emerald-100 bg-emerald-50 text-emerald-700'
}`
}
role=
{
resendStatus
===
'error'
?
'alert'
:
undefined
}
aria
-
live=
"polite"
>
{
resendMessage
}
</
div
>
)
}
...
...
@@ -157,6 +165,19 @@ export const Login: React.FC = () => {
</
div
>
</
form
>
<
div
className=
"text-center text-sm text-slate-500"
>
<
span
>
Chưa nhận được email xác thực?
</
span
>
<
button
type=
"button"
onClick=
{
()
=>
void
handleResendVerification
()
}
disabled=
{
resending
}
className=
"inline-flex min-h-11 items-center font-semibold text-indigo-600 hover:text-indigo-500 disabled:cursor-not-allowed disabled:opacity-60"
>
{
resending
&&
<
Loader2
className=
"mr-2 h-4 w-4 animate-spin"
/>
}
Gửi lại email xác thực
</
button
>
</
div
>
<
div
className=
"text-center text-sm text-slate-500"
>
Chưa có tài khoản?
{
' '
}
<
Link
to=
"/register"
className=
"font-medium text-indigo-600 hover:text-indigo-500 transition-colors"
>
...
...
tests/feedback-regression.test.mjs
View file @
b8e34e6e
...
...
@@ -20,6 +20,10 @@ test('login puts forgot-password below the password field and localizes invalid
);
assert
.
match
(
login
,
/Tài khoản hoặc mật khẩu không chính xác/
);
assert
.
match
(
login
,
/Gửi lại email xác thực/
);
assert
.
ok
(
login
.
indexOf
(
'</form>'
)
<
login
.
indexOf
(
'Gửi lại email xác thực'
),
'resend verification must always be visible below the login form'
,
);
});
test
(
'all requested password forms expose visibility controls'
,
()
=>
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment