import { cx, css } from '@emotion/css' import { useState } from 'react' import { useMutation } from '@tanstack/react-query' import { loginWithEmail, LoginWithEmailResponse, loginWithPhone, LoginWithPhoneResponse, } from '@/web/api/auth' import md5 from 'md5' import toast from 'react-hot-toast' import { setCookies } from '@/web/utils/cookie' import { AnimatePresence, motion } from 'framer-motion' import { ease } from '@/web/utils/const' import { useSnapshot } from 'valtio' import uiStates from '@/web/states/uiStates' import persistedUiStates from '@/web/states/persistedUiStates' import reactQueryClient from '@/web/utils/reactQueryClient' import { UserApiNames } from '@/shared/api/User' import { useTranslation } from 'react-i18next' const LoginWithPhoneOrEmail = () => { const { t, i18n } = useTranslation() const isZH = i18n.language.startsWith('zh') const { loginPhoneCountryCode, loginType: persistedLoginType } = useSnapshot(persistedUiStates) const [email, setEmail] = useState('') const [countryCode, setCountryCode] = useState( loginPhoneCountryCode || '+86' ) const [phone, setPhone] = useState('') const [password, setPassword] = useState('') const [loginType, setLoginType] = useState<'phone' | 'email'>( persistedLoginType === 'email' ? 'email' : 'phone' ) const handleAfterLogin = ( result: LoginWithEmailResponse | LoginWithPhoneResponse ) => { if (result?.code !== 200) return setCookies(result.cookie) reactQueryClient.refetchQueries([UserApiNames.FetchUserAccount]) uiStates.showLoginPanel = false } const handleError = (data: any, error: any) => { if (data?.code === 200) return toast( `Login failed: ${ data?.message || data?.msg || data?.error || error?.response?.data?.message || error?.response?.data?.msg || error }` ) } const doEmailLogin = useMutation( () => loginWithEmail({ email: email.trim(), md5_password: md5(password.trim()), }), { onSuccess: handleAfterLogin, onSettled: handleError } ) const handleEmailLogin = () => { if (!email) { toast.error('Please enter email') return } if (!password) { toast.error('Please enter password') return } if ( email.match( /^[^\s@]+@(126|163|yeah|188|vip\.163|vip\.126)\.(com|net)$/ ) == null ) { toast.error('Please use netease email') return } doEmailLogin.mutate() } const doPhoneLogin = useMutation( () => { return loginWithPhone({ countrycode: Number(countryCode.replace('+', '').trim()) || 86, phone: phone.trim(), md5_password: md5(password.trim()), }) }, { onSuccess: handleAfterLogin, onSettled: handleError } ) const handlePhoneLogin = () => { if (!countryCode || !Number(countryCode.replace('+', '').trim())) { toast.error('Please enter country code') return } if (!phone) { toast.error('Please enter phone number') return } if (!password) { toast.error('Please enter password') return } doPhoneLogin.mutate() } const transition = { duration: 0.5, ease, } const variants = { hidden: { opacity: 0, transition, }, show: { opacity: 1, transition, }, } return ( <>
{!isZH && 'Login with '} { const type = loginType === 'phone' ? 'email' : 'phone' setLoginType(type) persistedUiStates.loginType = type }} > {t`auth.phone`} {isZH && '登录'} {' / '} { if (loginType !== 'email') setLoginType('email') }} > {t`auth.email`} {isZH && '登录'}
{/* Phone input */} {loginType === 'phone' && (
{ setCountryCode(e.target.value) persistedUiStates.loginPhoneCountryCode = e.target.value }} className={cx( 'my-3.5 flex-shrink-0 bg-transparent placeholder:text-white/30', css` width: 28px; ` )} placeholder='+86' value={countryCode} />
setPhone(e.target.value)} className='my-3.5 flex-grow appearance-none bg-transparent placeholder:text-white/30' placeholder={t`auth.phone`} type='tel' value={phone} />
)} {/* Email input */} {loginType === 'email' && (
setEmail(e.target.value)} className='w-full flex-grow appearance-none bg-transparent placeholder:text-white/30' placeholder={t`auth.email`} type='email' value={email} />
)} {/* Password input */}
setPassword(e.target.value)} className='w-full bg-transparent placeholder:text-white/30' placeholder={t`auth.password`} type='password' value={password} />
{/* Login button */}
loginType === 'phone' ? handlePhoneLogin() : handleEmailLogin() } className='mt-4 rounded-full bg-brand-700 p-4 text-center text-16 font-medium text-white' > {t`auth.login`}
) } export default LoginWithPhoneOrEmail