mirror of
https://github.com/toeverything/AFFiNE.git
synced 2024-08-17 23:50:37 +03:00
feat(core): make password sigin default if user has one (#5577)
This commit is contained in:
parent
bf88b6edaa
commit
b9f20877d0
@ -17,7 +17,7 @@ export const AuthModal: FC<PropsWithChildren<AuthModalProps>> = ({
|
||||
open={open}
|
||||
onOpenChange={setOpen}
|
||||
width={400}
|
||||
height={468}
|
||||
minHeight={500}
|
||||
contentOptions={{
|
||||
['data-testid' as string]: 'auth-modal',
|
||||
style: { padding: '44px 40px 0' },
|
||||
|
@ -53,9 +53,12 @@ export const AfterSignInSendEmail = ({
|
||||
subTitle={t['com.affine.auth.sign.in.sent.email.subtitle']()}
|
||||
/>
|
||||
<AuthContent style={{ height: 100 }}>
|
||||
{t['com.affine.auth.sign.sent.email.message.start']()}
|
||||
<a href={`mailto:${email}`}>{email}</a>
|
||||
{t['com.affine.auth.sign.sent.email.message.end']()}
|
||||
<Trans
|
||||
i18nKey="com.affine.auth.sign.sent.email.message.sent-tips"
|
||||
values={{ email }}
|
||||
components={{ a: <a href={`mailto:${email}`} /> }}
|
||||
/>
|
||||
{t['com.affine.auth.sign.sent.email.message.sent-tips.sign-in']()}
|
||||
</AuthContent>
|
||||
|
||||
<div className={style.resendWrapper}>
|
||||
@ -73,15 +76,15 @@ export const AfterSignInSendEmail = ({
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<span className="resend-code-hint">
|
||||
{t['com.affine.auth.sign.auth.code.on.resend.hint']()}
|
||||
</span>
|
||||
<div className={style.sentRow}>
|
||||
<div className={style.sentMessage}>
|
||||
{t['com.affine.auth.sent']()}
|
||||
</div>
|
||||
<CountDownRender
|
||||
className={style.resendCountdown}
|
||||
timeLeft={resendCountDown}
|
||||
/>
|
||||
</>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -90,16 +93,18 @@ export const AfterSignInSendEmail = ({
|
||||
{subscriptionData ? null : ( // If with payment, just support email sign in to avoid duplicate redirect to the same stripe url.
|
||||
<React.Fragment>
|
||||
|
||||
{/*prettier-ignore*/}
|
||||
<Trans i18nKey="com.affine.auth.sign.auth.code.message.password">
|
||||
Or <span
|
||||
className="link"
|
||||
data-testid='sign-in-with-password'
|
||||
onClick={onSignInWithPasswordClick}
|
||||
>
|
||||
sign in with password
|
||||
</span> instead.
|
||||
</Trans>
|
||||
<Trans
|
||||
i18nKey="com.affine.auth.sign.auth.code.message.password"
|
||||
components={{
|
||||
1: (
|
||||
<span
|
||||
className="link"
|
||||
data-testid="sign-in-with-password"
|
||||
onClick={onSignInWithPasswordClick}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</React.Fragment>
|
||||
)}
|
||||
</div>
|
||||
|
@ -6,6 +6,7 @@ import {
|
||||
} from '@affine/component/auth-components';
|
||||
import { Button } from '@affine/component/ui/button';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { Trans } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { type FC, useCallback } from 'react';
|
||||
|
||||
@ -43,9 +44,12 @@ export const AfterSignUpSendEmail: FC<AuthPanelProps> = ({
|
||||
subTitle={t['com.affine.auth.sign.up.sent.email.subtitle']()}
|
||||
/>
|
||||
<AuthContent style={{ height: 100 }}>
|
||||
{t['com.affine.auth.sign.sent.email.message.start']()}
|
||||
<a href={`mailto:${email}`}>{email}</a>
|
||||
{t['com.affine.auth.sign.sent.email.message.end']()}
|
||||
<Trans
|
||||
i18nKey="com.affine.auth.sign.sent.email.message.sent-tips"
|
||||
values={{ email }}
|
||||
components={{ a: <a href={`mailto:${email}`} /> }}
|
||||
/>
|
||||
{t['com.affine.auth.sign.sent.email.message.sent-tips.sign-up']()}
|
||||
</AuthContent>
|
||||
|
||||
<div className={style.resendWrapper}>
|
||||
@ -63,15 +67,15 @@ export const AfterSignUpSendEmail: FC<AuthPanelProps> = ({
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<span className="resend-code-hint">
|
||||
{t['com.affine.auth.sign.auth.code.on.resend.hint']()}
|
||||
</span>
|
||||
<div className={style.sentRow}>
|
||||
<div className={style.sentMessage}>
|
||||
{t['com.affine.auth.sent']()}
|
||||
</div>
|
||||
<CountDownRender
|
||||
className={style.resendCountdown}
|
||||
timeLeft={resendCountDown}
|
||||
/>
|
||||
</>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
@ -39,7 +39,7 @@ const useContent = (emailType: AuthPanelProps['emailType'], email: string) => {
|
||||
case 'setPassword':
|
||||
return t['com.affine.auth.set.password.message']();
|
||||
case 'changePassword':
|
||||
return t['com.affine.auth.set.password.message']();
|
||||
return t['com.affine.auth.reset.password.message']();
|
||||
case 'changeEmail':
|
||||
return t['com.affine.auth.change.email.message']({
|
||||
email,
|
||||
|
@ -14,10 +14,13 @@ import { useCallback, useState } from 'react';
|
||||
|
||||
import { signInCloud } from '../../../utils/cloud-utils';
|
||||
import type { AuthPanelProps } from './index';
|
||||
import { forgetPasswordButton } from './style.css';
|
||||
import * as styles from './style.css';
|
||||
import { INTERNAL_BETA_URL, useAuth } from './use-auth';
|
||||
import { useCaptcha } from './use-captcha';
|
||||
|
||||
export const SignInWithPassword: FC<AuthPanelProps> = ({
|
||||
setAuthState,
|
||||
setEmailType,
|
||||
email,
|
||||
onSignedIn,
|
||||
}) => {
|
||||
@ -26,6 +29,13 @@ export const SignInWithPassword: FC<AuthPanelProps> = ({
|
||||
|
||||
const [password, setPassword] = useState('');
|
||||
const [passwordError, setPasswordError] = useState(false);
|
||||
const {
|
||||
signIn,
|
||||
allowSendEmail,
|
||||
resetCountDown,
|
||||
isMutating: sendingEmail,
|
||||
} = useAuth();
|
||||
const [verifyToken, challenge] = useCaptcha();
|
||||
|
||||
const onSignIn = useAsyncCallback(async () => {
|
||||
const res = await signInCloud('credentials', {
|
||||
@ -42,6 +52,31 @@ export const SignInWithPassword: FC<AuthPanelProps> = ({
|
||||
onSignedIn?.();
|
||||
}, [email, password, onSignedIn, update]);
|
||||
|
||||
const sendMagicLink = useAsyncCallback(async () => {
|
||||
if (allowSendEmail && verifyToken && !sendingEmail) {
|
||||
const res = await signIn(email, verifyToken, challenge);
|
||||
if (res?.status === 403 && res?.url === INTERNAL_BETA_URL) {
|
||||
resetCountDown();
|
||||
return setAuthState('noAccess');
|
||||
}
|
||||
setAuthState('afterSignInSendEmail');
|
||||
}
|
||||
}, [
|
||||
email,
|
||||
signIn,
|
||||
allowSendEmail,
|
||||
sendingEmail,
|
||||
setAuthState,
|
||||
verifyToken,
|
||||
challenge,
|
||||
resetCountDown,
|
||||
]);
|
||||
|
||||
const sendChangePasswordEmail = useCallback(() => {
|
||||
setEmailType('changePassword');
|
||||
setAuthState('sendEmail');
|
||||
}, [setAuthState, setEmailType]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ModalHeader
|
||||
@ -51,7 +86,6 @@ export const SignInWithPassword: FC<AuthPanelProps> = ({
|
||||
|
||||
<Wrapper
|
||||
marginTop={30}
|
||||
marginBottom={50}
|
||||
style={{
|
||||
position: 'relative',
|
||||
}}
|
||||
@ -73,29 +107,43 @@ export const SignInWithPassword: FC<AuthPanelProps> = ({
|
||||
errorHint={t['com.affine.auth.password.error']()}
|
||||
onEnter={onSignIn}
|
||||
/>
|
||||
<span></span>
|
||||
<button
|
||||
className={forgetPasswordButton}
|
||||
// onClick={useCallback(() => {
|
||||
// setAuthState('sendPasswordEmail');
|
||||
// }, [setAuthState])}
|
||||
<div
|
||||
className={styles.forgetPasswordButtonRow}
|
||||
style={{ display: 'none' }} // Not implemented yet.
|
||||
>
|
||||
{t['com.affine.auth.forget']()}
|
||||
</button>
|
||||
<a
|
||||
className={styles.linkButton}
|
||||
onClick={sendChangePasswordEmail}
|
||||
style={{
|
||||
color: 'var(--affine-text-secondary-color)',
|
||||
fontSize: 'var(--affine-font-sm)',
|
||||
}}
|
||||
>
|
||||
{t['com.affine.auth.forget']()}
|
||||
</a>
|
||||
</div>
|
||||
<div className={styles.sendMagicLinkButtonRow}>
|
||||
<a
|
||||
data-testid="send-magic-link-button"
|
||||
className={styles.linkButton}
|
||||
onClick={sendMagicLink}
|
||||
>
|
||||
{t['com.affine.auth.sign.auth.code.send-email.sign-in']()}
|
||||
</a>
|
||||
</div>
|
||||
<Button
|
||||
data-testid="sign-in-button"
|
||||
type="primary"
|
||||
size="extraLarge"
|
||||
style={{ width: '100%' }}
|
||||
onClick={onSignIn}
|
||||
>
|
||||
{t['com.affine.auth.sign.in']()}
|
||||
</Button>
|
||||
</Wrapper>
|
||||
<Button
|
||||
data-testid="sign-in-button"
|
||||
type="primary"
|
||||
size="extraLarge"
|
||||
style={{ width: '100%' }}
|
||||
onClick={onSignIn}
|
||||
>
|
||||
{t['com.affine.auth.sign.in']()}
|
||||
</Button>
|
||||
|
||||
<BackButton
|
||||
onClick={useCallback(() => {
|
||||
setAuthState('afterSignInSendEmail');
|
||||
setAuthState('signIn');
|
||||
}, [setAuthState])}
|
||||
/>
|
||||
</>
|
||||
|
@ -61,16 +61,13 @@ export const SignIn: FC<AuthPanelProps> = ({
|
||||
|
||||
setIsValidEmail(true);
|
||||
// 0 for no access for internal beta
|
||||
let user: GetUserQuery['user'] | null | 0 = null;
|
||||
await verifyUser({ email })
|
||||
.then(({ user: u }) => {
|
||||
user = u;
|
||||
})
|
||||
const user: GetUserQuery['user'] | null | 0 = await verifyUser({ email })
|
||||
.then(({ user }) => user)
|
||||
.catch(err => {
|
||||
const e = err?.[0];
|
||||
if (e instanceof GraphQLError && e.extensions?.code === 402) {
|
||||
setAuthState('noAccess');
|
||||
user = 0;
|
||||
return 0;
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
@ -83,11 +80,16 @@ export const SignIn: FC<AuthPanelProps> = ({
|
||||
|
||||
if (verifyToken) {
|
||||
if (user) {
|
||||
const res = await signIn(email, verifyToken, challenge);
|
||||
if (res?.status === 403 && res?.url === INTERNAL_BETA_URL) {
|
||||
return setAuthState('noAccess');
|
||||
// provider password sign-in if user has by default
|
||||
if (user.hasPassword) {
|
||||
setAuthState('signInWithPassword');
|
||||
} else {
|
||||
const res = await signIn(email, verifyToken, challenge);
|
||||
if (res?.status === 403 && res?.url === INTERNAL_BETA_URL) {
|
||||
return setAuthState('noAccess');
|
||||
}
|
||||
setAuthState('afterSignInSendEmail');
|
||||
}
|
||||
setAuthState('afterSignInSendEmail');
|
||||
} else {
|
||||
const res = await signUp(email, verifyToken, challenge);
|
||||
if (res?.status === 403 && res?.url === INTERNAL_BETA_URL) {
|
||||
|
@ -24,13 +24,30 @@ globalStyle(`${authMessage} .link`, {
|
||||
color: 'var(--affine-link-color)',
|
||||
});
|
||||
|
||||
export const forgetPasswordButtonRow = style({
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
marginTop: '-26px', // Let this button be a tail of password input.
|
||||
});
|
||||
export const sendMagicLinkButtonRow = style({
|
||||
marginBottom: '30px',
|
||||
});
|
||||
|
||||
export const linkButton = style({
|
||||
color: 'var(--affine-link-color)',
|
||||
background: 'transparent',
|
||||
borderColor: 'transparent',
|
||||
fontSize: 'var(--affine-font-xs)',
|
||||
lineHeight: '22px',
|
||||
userSelect: 'none',
|
||||
});
|
||||
|
||||
export const forgetPasswordButton = style({
|
||||
fontSize: 'var(--affine-font-sm)',
|
||||
color: 'var(--affine-text-secondary-color)',
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
display: 'none',
|
||||
});
|
||||
|
||||
export const resendWrapper = style({
|
||||
@ -42,7 +59,21 @@ export const resendWrapper = style({
|
||||
marginTop: 30,
|
||||
});
|
||||
|
||||
export const resendCountdown = style({ width: 45, textAlign: 'center' });
|
||||
export const sentRow = style({
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
gap: '8px',
|
||||
lineHeight: '22px',
|
||||
fontSize: 'var(--affine-font-sm)',
|
||||
});
|
||||
export const sentMessage = style({
|
||||
color: 'var(--affine-text-primary-color)',
|
||||
fontWeight: 600,
|
||||
});
|
||||
export const resendCountdown = style({
|
||||
width: 45,
|
||||
textAlign: 'center',
|
||||
});
|
||||
export const resendCountdownInButton = style({
|
||||
width: 40,
|
||||
textAlign: 'center',
|
||||
|
@ -150,9 +150,18 @@ export const useAuth = () => {
|
||||
signInCloud('google').catch(console.error);
|
||||
}, []);
|
||||
|
||||
const resetCountDown = useCallback(() => {
|
||||
setAuthStore({
|
||||
isMutating: false,
|
||||
allowSendEmail: false,
|
||||
resendCountDown: 0,
|
||||
});
|
||||
}, [setAuthStore]);
|
||||
|
||||
return {
|
||||
allowSendEmail: authStore.allowSendEmail,
|
||||
resendCountDown: authStore.resendCountDown,
|
||||
resetCountDown,
|
||||
isMutating: authStore.isMutating,
|
||||
signUp,
|
||||
signIn,
|
||||
|
@ -454,8 +454,8 @@
|
||||
"com.affine.auth.sign.auth.code.error.hint": "Wrong code, please try again",
|
||||
"com.affine.auth.sign.auth.code.message": "If you haven't received the email, please check your spam folder.",
|
||||
"com.affine.auth.sign.auth.code.message.password": "Or <1>sign in with password</1> instead.",
|
||||
"com.affine.auth.sign.auth.code.on.resend.hint": "Send code again",
|
||||
"com.affine.auth.sign.auth.code.resend.hint": "Resend code",
|
||||
"com.affine.auth.sign.auth.code.resend.hint": "Resend link",
|
||||
"com.affine.auth.sign.auth.code.send-email.sign-in": "Sign in with magic link",
|
||||
"com.affine.auth.sign.condition": "Terms of Conditions",
|
||||
"com.affine.auth.sign.email.continue": "Continue with Email",
|
||||
"com.affine.auth.sign.email.error": "Invalid email",
|
||||
@ -467,8 +467,9 @@
|
||||
"com.affine.auth.sign.no.access.link": "AFFiNE Cloud Early Access",
|
||||
"com.affine.auth.sign.no.access.wait": "Wait for public release",
|
||||
"com.affine.auth.sign.policy": "Privacy Policy",
|
||||
"com.affine.auth.sign.sent.email.message.end": " You can click the link to create an account automatically.",
|
||||
"com.affine.auth.sign.sent.email.message.start": "An email with a magic link has been sent to ",
|
||||
"com.affine.auth.sign.sent.email.message.sent-tips": "An email with a magic link has been sent to <a>{{email}}</a>.",
|
||||
"com.affine.auth.sign.sent.email.message.sent-tips.sign-up": "You can click the link to create an account automatically.",
|
||||
"com.affine.auth.sign.sent.email.message.sent-tips.sign-in": "You can click the link to sign in automatically.",
|
||||
"com.affine.auth.sign.up": "Sign up",
|
||||
"com.affine.auth.sign.up.sent.email.subtitle": "Create your account",
|
||||
"com.affine.auth.sign.up.success.subtitle": "The app will automatically open or redirect to the web version. If you encounter any issues, you can also click the button below to manually open the AFFiNE app.",
|
||||
|
@ -443,7 +443,8 @@
|
||||
"com.affine.auth.sign.auth.code.message": "如果您没有收到电子邮件,请检查您的垃圾邮件文件夹。",
|
||||
"com.affine.auth.sign.auth.code.message.password": "或者使用<1>密码登录</1>。",
|
||||
"com.affine.auth.sign.auth.code.on.resend.hint": "再次发送验证码",
|
||||
"com.affine.auth.sign.auth.code.resend.hint": "重发验证码",
|
||||
"com.affine.auth.sign.auth.code.sent-tips": "重发验证码",
|
||||
"com.affine.auth.sign.auth.code.send-email.sign-in": "邮件登录",
|
||||
"com.affine.auth.sign.condition": "条款与条件",
|
||||
"com.affine.auth.sign.email.continue": "以电子邮件继续",
|
||||
"com.affine.auth.sign.email.error": "无效的电子邮件",
|
||||
@ -456,7 +457,8 @@
|
||||
"com.affine.auth.sign.no.access.wait": "请期待正式发行",
|
||||
"com.affine.auth.sign.policy": "隐私政策",
|
||||
"com.affine.auth.sign.sent.email.message.end": "您可以点击链接自动创建账户。",
|
||||
"com.affine.auth.sign.sent.email.message.start": "一封带有 magic link 的邮件已发送至",
|
||||
"com.affine.auth.sign.sent.email.message.sign-in.end": "您可以点击链接自动登录。",
|
||||
"com.affine.auth.sign.sent.email.message.sent-tips": "一封带有 magic link 的邮件已发送至 <a>{{email}}</a>。",
|
||||
"com.affine.auth.sign.up": "注册",
|
||||
"com.affine.auth.sign.up.sent.email.subtitle": "创建您的账号",
|
||||
"com.affine.auth.sign.up.success.subtitle": "AFFiNE 客户端将自动打开或重定向到网页端,如果您遇到任何问题,可以点击下方按钮手动打开 AFFiNE。",
|
||||
|
@ -365,7 +365,7 @@
|
||||
"com.affine.auth.sign.message": "點擊上方「使用 Google/電子郵件地址 繼續」,即表示您確認同意 AFFiNE 的 <1>Terms of Conditions</1> and <3>Privacy Policy</3>。",
|
||||
"com.affine.auth.sign.policy": "隱私政策",
|
||||
"com.affine.auth.sign.sent.email.message.end": "您可以點擊連結自動建立帳號。",
|
||||
"com.affine.auth.sign.sent.email.message.start": "一封帶有魔法連結的電子郵件已發送至",
|
||||
"com.affine.auth.sign.sent.email.message.sent-tips": "一封帶有魔法連結的電子郵件已發送至 <a>{{email}}</a>。",
|
||||
"com.affine.auth.sign.up": "建立帳號",
|
||||
"com.affine.auth.sign.up.sent.email.subtitle": "建立您的帳號",
|
||||
"com.affine.auth.sign.up.success.subtitle": "應用將自動打開或重定向到網頁版本。如果您遇到任何問題,您還可以點擊下面的按鈕手動打開 AFFiNE 應用程序。",
|
||||
|
@ -170,9 +170,6 @@ export async function loginUser(
|
||||
await page.getByTestId('continue-login-button').click({
|
||||
delay: 200,
|
||||
});
|
||||
await page.getByTestId('sign-in-with-password').click({
|
||||
delay: 200,
|
||||
});
|
||||
await page.getByTestId('password-input').fill('123456');
|
||||
if (config?.beforeLogin) {
|
||||
await config.beforeLogin();
|
||||
|
Loading…
Reference in New Issue
Block a user