Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

page.tsx 4.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. 'use client'
  2. import { useCallback, useState } from 'react'
  3. import { useTranslation } from 'react-i18next'
  4. import { useRouter, useSearchParams } from 'next/navigation'
  5. import cn from 'classnames'
  6. import Button from '@/app/components/base/button'
  7. import Toast from '@/app/components/base/toast'
  8. import Input from '@/app/components/base/input'
  9. import { validPassword } from '@/config'
  10. import type { MailRegisterResponse } from '@/service/use-common'
  11. import { useMailRegister } from '@/service/use-common'
  12. const ChangePasswordForm = () => {
  13. const { t } = useTranslation()
  14. const router = useRouter()
  15. const searchParams = useSearchParams()
  16. const token = decodeURIComponent(searchParams.get('token') || '')
  17. const [password, setPassword] = useState('')
  18. const [confirmPassword, setConfirmPassword] = useState('')
  19. const { mutateAsync: register, isPending } = useMailRegister()
  20. const showErrorMessage = useCallback((message: string) => {
  21. Toast.notify({
  22. type: 'error',
  23. message,
  24. })
  25. }, [])
  26. const valid = useCallback(() => {
  27. if (!password.trim()) {
  28. showErrorMessage(t('login.error.passwordEmpty'))
  29. return false
  30. }
  31. if (!validPassword.test(password)) {
  32. showErrorMessage(t('login.error.passwordInvalid'))
  33. return false
  34. }
  35. if (password !== confirmPassword) {
  36. showErrorMessage(t('common.account.notEqual'))
  37. return false
  38. }
  39. return true
  40. }, [password, confirmPassword, showErrorMessage, t])
  41. const handleSubmit = useCallback(async () => {
  42. if (!valid())
  43. return
  44. try {
  45. const res = await register({
  46. token,
  47. new_password: password,
  48. password_confirm: confirmPassword,
  49. })
  50. const { result, data } = res as MailRegisterResponse
  51. if (result === 'success') {
  52. Toast.notify({
  53. type: 'success',
  54. message: t('common.api.actionSuccess'),
  55. })
  56. localStorage.setItem('console_token', data.access_token)
  57. localStorage.setItem('refresh_token', data.refresh_token)
  58. router.replace('/apps')
  59. }
  60. }
  61. catch (error) {
  62. console.error(error)
  63. }
  64. }, [password, token, valid, confirmPassword, register])
  65. return (
  66. <div className={
  67. cn(
  68. 'flex w-full grow flex-col items-center justify-center',
  69. 'px-6',
  70. 'md:px-[108px]',
  71. )
  72. }>
  73. <div className='flex flex-col md:w-[400px]'>
  74. <div className="mx-auto w-full">
  75. <h2 className="title-4xl-semi-bold text-text-primary">
  76. {t('login.changePassword')}
  77. </h2>
  78. <p className='body-md-regular mt-2 text-text-secondary'>
  79. {t('login.changePasswordTip')}
  80. </p>
  81. </div>
  82. <div className="mx-auto mt-6 w-full">
  83. <div>
  84. {/* Password */}
  85. <div className='mb-5'>
  86. <label htmlFor="password" className="system-md-semibold my-2 text-text-secondary">
  87. {t('common.account.newPassword')}
  88. </label>
  89. <div className='relative mt-1'>
  90. <Input
  91. id="password"
  92. type='password'
  93. value={password}
  94. onChange={e => setPassword(e.target.value)}
  95. placeholder={t('login.passwordPlaceholder') || ''}
  96. />
  97. </div>
  98. <div className='body-xs-regular mt-1 text-text-secondary'>{t('login.error.passwordInvalid')}</div>
  99. </div>
  100. {/* Confirm Password */}
  101. <div className='mb-5'>
  102. <label htmlFor="confirmPassword" className="system-md-semibold my-2 text-text-secondary">
  103. {t('common.account.confirmPassword')}
  104. </label>
  105. <div className='relative mt-1'>
  106. <Input
  107. id="confirmPassword"
  108. type='password'
  109. value={confirmPassword}
  110. onChange={e => setConfirmPassword(e.target.value)}
  111. placeholder={t('login.confirmPasswordPlaceholder') || ''}
  112. />
  113. </div>
  114. </div>
  115. <div>
  116. <Button
  117. variant='primary'
  118. className='w-full'
  119. onClick={handleSubmit}
  120. disabled={isPending || !password || !confirmPassword}
  121. >
  122. {t('login.changePasswordBtn')}
  123. </Button>
  124. </div>
  125. </div>
  126. </div>
  127. </div>
  128. </div>
  129. )
  130. }
  131. export default ChangePasswordForm