123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- import Link from 'next/link'
- import { useState } from 'react'
- import { useTranslation } from 'react-i18next'
- import { useRouter, useSearchParams } from 'next/navigation'
- import { useContext } from 'use-context-selector'
- import Button from '@/app/components/base/button'
- import Toast from '@/app/components/base/toast'
- import { emailRegex } from '@/config'
- import { login } from '@/service/common'
- import Input from '@/app/components/base/input'
- import I18NContext from '@/context/i18n'
- type MailAndPasswordAuthProps = {
- isInvite: boolean
- allowRegistration: boolean
- }
- const passwordRegex = /^(?=.*[a-zA-Z])(?=.*\d).{8,}$/
- export default function MailAndPasswordAuth({ isInvite, allowRegistration }: MailAndPasswordAuthProps) {
- const { t } = useTranslation()
- const { locale } = useContext(I18NContext)
- const router = useRouter()
- const searchParams = useSearchParams()
- const [showPassword, setShowPassword] = useState(false)
- const emailFromLink = decodeURIComponent(searchParams.get('email') || '')
- const [email, setEmail] = useState(emailFromLink)
- const [password, setPassword] = useState('')
- const [isLoading, setIsLoading] = useState(false)
- const handleEmailPasswordLogin = async () => {
- if (!email) {
- Toast.notify({ type: 'error', message: t('login.error.emailEmpty') })
- return
- }
- if (!emailRegex.test(email)) {
- Toast.notify({
- type: 'error',
- message: t('login.error.emailInValid'),
- })
- return
- }
- if (!password?.trim()) {
- Toast.notify({ type: 'error', message: t('login.error.passwordEmpty') })
- return
- }
- if (!passwordRegex.test(password)) {
- Toast.notify({
- type: 'error',
- message: t('login.error.passwordInvalid'),
- })
- return
- }
- try {
- setIsLoading(true)
- const loginData: Record<string, any> = {
- email,
- password,
- language: locale,
- remember_me: true,
- }
- if (isInvite)
- loginData.invite_token = decodeURIComponent(searchParams.get('invite_token') as string)
- const res = await login({
- url: '/login',
- body: loginData,
- })
- if (res.result === 'success') {
- if (isInvite) {
- router.replace(`/signin/invite-settings?${searchParams.toString()}`)
- }
- else {
- localStorage.setItem('console_token', res.data.access_token)
- localStorage.setItem('refresh_token', res.data.refresh_token)
- router.replace('/apps')
- }
- }
- else if (res.code === 'account_not_found') {
- if (allowRegistration) {
- const params = new URLSearchParams()
- params.append('email', encodeURIComponent(email))
- params.append('token', encodeURIComponent(res.data))
- router.replace(`/reset-password/check-code?${params.toString()}`)
- }
- else {
- Toast.notify({
- type: 'error',
- message: t('login.error.registrationNotAllowed'),
- })
- }
- }
- else {
- Toast.notify({
- type: 'error',
- message: res.data,
- })
- }
- }
- finally {
- setIsLoading(false)
- }
- }
- return <form onSubmit={() => { }}>
- {/* 登录页输入框 */}
- <div className='mb-3'>
- <label htmlFor="email" className="my-2 system-md-semibold text-text-secondary">
- {t('login.email')}
- </label>
- <div className="mt-1">
- <Input
- value={email}
- onChange={e => setEmail(e.target.value)}
- disabled={isInvite}
- id="email"
- type="email"
- autoComplete="email"
- placeholder={t('login.emailPlaceholder') || ''}
- tabIndex={1}
- />
- </div>
- </div>
- <div className='mb-3'>
- <label htmlFor="password" className="my-2 flex items-center justify-between">
- <span className='system-md-semibold text-text-secondary'>{t('login.password')}</span>
-
- </label>
- <div className="relative mt-1">
- <Input
- id="password"
- value={password}
- onChange={e => setPassword(e.target.value)}
- onKeyDown={(e) => {
- if (e.key === 'Enter')
- handleEmailPasswordLogin()
- }}
- type={showPassword ? 'text' : 'password'}
- autoComplete="current-password"
- placeholder={t('login.passwordPlaceholder') || ''}
- tabIndex={2}
- />
- {/* <div className="absolute inset-y-0 right-0 flex items-center">
- <Button
- type="button"
- variant='ghost'
- onClick={() => setShowPassword(!showPassword)}
- >
- {showPassword ? '👀' : '😝'}
- </Button>
- </div> */}
- </div>
- <div style={{textAlign: 'right'}}>
- <Link href={`/reset-password?${searchParams.toString()}`} className='system-xs-regular text-components-button-secondary-accent-text'>
- {t('login.forget')}
- </Link>
- </div>
-
- </div>
- <div className='mb-2'>
- <Button
- tabIndex={2}
- variant='primary'
- onClick={handleEmailPasswordLogin}
- disabled={isLoading || !email || !password}
- className="w-full"
- >{t('login.signBtn')}</Button>
- </div>
- </form>
- }
|