From b9f20877d0f6dcbaffe501828f816b170101478d Mon Sep 17 00:00:00 2001 From: liuyi Date: Wed, 17 Jan 2024 11:13:58 +0000 Subject: [PATCH] feat(core): make password sigin default if user has one (#5577) --- .../src/components/auth-components/modal.tsx | 2 +- .../affine/auth/after-sign-in-send-email.tsx | 41 +++++---- .../affine/auth/after-sign-up-send-email.tsx | 20 +++-- .../src/components/affine/auth/send-email.tsx | 2 +- .../affine/auth/sign-in-with-password.tsx | 90 ++++++++++++++----- .../src/components/affine/auth/sign-in.tsx | 22 ++--- .../src/components/affine/auth/style.css.ts | 35 +++++++- .../src/components/affine/auth/use-auth.ts | 9 ++ packages/frontend/i18n/src/resources/en.json | 9 +- .../frontend/i18n/src/resources/zh-Hans.json | 6 +- .../frontend/i18n/src/resources/zh-Hant.json | 2 +- tests/kit/utils/cloud.ts | 3 - 12 files changed, 170 insertions(+), 71 deletions(-) diff --git a/packages/frontend/component/src/components/auth-components/modal.tsx b/packages/frontend/component/src/components/auth-components/modal.tsx index 856196380..8406754b6 100644 --- a/packages/frontend/component/src/components/auth-components/modal.tsx +++ b/packages/frontend/component/src/components/auth-components/modal.tsx @@ -17,7 +17,7 @@ export const AuthModal: FC> = ({ open={open} onOpenChange={setOpen} width={400} - height={468} + minHeight={500} contentOptions={{ ['data-testid' as string]: 'auth-modal', style: { padding: '44px 40px 0' }, diff --git a/packages/frontend/core/src/components/affine/auth/after-sign-in-send-email.tsx b/packages/frontend/core/src/components/affine/auth/after-sign-in-send-email.tsx index e3bdcf220..c4c728122 100644 --- a/packages/frontend/core/src/components/affine/auth/after-sign-in-send-email.tsx +++ b/packages/frontend/core/src/components/affine/auth/after-sign-in-send-email.tsx @@ -53,9 +53,12 @@ export const AfterSignInSendEmail = ({ subTitle={t['com.affine.auth.sign.in.sent.email.subtitle']()} /> - {t['com.affine.auth.sign.sent.email.message.start']()} - {email} - {t['com.affine.auth.sign.sent.email.message.end']()} + }} + /> + {t['com.affine.auth.sign.sent.email.message.sent-tips.sign-in']()}
@@ -73,15 +76,15 @@ export const AfterSignInSendEmail = ({ ) : ( - <> - - {t['com.affine.auth.sign.auth.code.on.resend.hint']()} - +
+
+ {t['com.affine.auth.sent']()} +
- +
)}
@@ -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.   - {/*prettier-ignore*/} - - Or - sign in with password - instead. - + + ), + }} + /> )} diff --git a/packages/frontend/core/src/components/affine/auth/after-sign-up-send-email.tsx b/packages/frontend/core/src/components/affine/auth/after-sign-up-send-email.tsx index fd7c754bb..99890b0be 100644 --- a/packages/frontend/core/src/components/affine/auth/after-sign-up-send-email.tsx +++ b/packages/frontend/core/src/components/affine/auth/after-sign-up-send-email.tsx @@ -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 = ({ subTitle={t['com.affine.auth.sign.up.sent.email.subtitle']()} /> - {t['com.affine.auth.sign.sent.email.message.start']()} - {email} - {t['com.affine.auth.sign.sent.email.message.end']()} + }} + /> + {t['com.affine.auth.sign.sent.email.message.sent-tips.sign-up']()}
@@ -63,15 +67,15 @@ export const AfterSignUpSendEmail: FC = ({ ) : ( - <> - - {t['com.affine.auth.sign.auth.code.on.resend.hint']()} - +
+
+ {t['com.affine.auth.sent']()} +
- +
)}
diff --git a/packages/frontend/core/src/components/affine/auth/send-email.tsx b/packages/frontend/core/src/components/affine/auth/send-email.tsx index c96d7934a..91b3a6330 100644 --- a/packages/frontend/core/src/components/affine/auth/send-email.tsx +++ b/packages/frontend/core/src/components/affine/auth/send-email.tsx @@ -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, diff --git a/packages/frontend/core/src/components/affine/auth/sign-in-with-password.tsx b/packages/frontend/core/src/components/affine/auth/sign-in-with-password.tsx index 2d4e3312f..bb649bd9d 100644 --- a/packages/frontend/core/src/components/affine/auth/sign-in-with-password.tsx +++ b/packages/frontend/core/src/components/affine/auth/sign-in-with-password.tsx @@ -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 = ({ setAuthState, + setEmailType, email, onSignedIn, }) => { @@ -26,6 +29,13 @@ export const SignInWithPassword: FC = ({ 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 = ({ 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 ( <> = ({ = ({ errorHint={t['com.affine.auth.password.error']()} onEnter={onSignIn} /> - - + + {t['com.affine.auth.forget']()} + + + + - - { - setAuthState('afterSignInSendEmail'); + setAuthState('signIn'); }, [setAuthState])} /> diff --git a/packages/frontend/core/src/components/affine/auth/sign-in.tsx b/packages/frontend/core/src/components/affine/auth/sign-in.tsx index f3885a157..a43d7b7c0 100644 --- a/packages/frontend/core/src/components/affine/auth/sign-in.tsx +++ b/packages/frontend/core/src/components/affine/auth/sign-in.tsx @@ -61,16 +61,13 @@ export const SignIn: FC = ({ 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 = ({ 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) { diff --git a/packages/frontend/core/src/components/affine/auth/style.css.ts b/packages/frontend/core/src/components/affine/auth/style.css.ts index a8331464f..e03f57039 100644 --- a/packages/frontend/core/src/components/affine/auth/style.css.ts +++ b/packages/frontend/core/src/components/affine/auth/style.css.ts @@ -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', diff --git a/packages/frontend/core/src/components/affine/auth/use-auth.ts b/packages/frontend/core/src/components/affine/auth/use-auth.ts index e2b338b01..dac05ec1f 100644 --- a/packages/frontend/core/src/components/affine/auth/use-auth.ts +++ b/packages/frontend/core/src/components/affine/auth/use-auth.ts @@ -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, diff --git a/packages/frontend/i18n/src/resources/en.json b/packages/frontend/i18n/src/resources/en.json index b99ad542b..34fdb4907 100644 --- a/packages/frontend/i18n/src/resources/en.json +++ b/packages/frontend/i18n/src/resources/en.json @@ -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 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 {{email}}.", + "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.", diff --git a/packages/frontend/i18n/src/resources/zh-Hans.json b/packages/frontend/i18n/src/resources/zh-Hans.json index 54a6b9c7a..4a02b375d 100644 --- a/packages/frontend/i18n/src/resources/zh-Hans.json +++ b/packages/frontend/i18n/src/resources/zh-Hans.json @@ -443,7 +443,8 @@ "com.affine.auth.sign.auth.code.message": "如果您没有收到电子邮件,请检查您的垃圾邮件文件夹。", "com.affine.auth.sign.auth.code.message.password": "或者使用<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 的邮件已发送至 {{email}}。", "com.affine.auth.sign.up": "注册", "com.affine.auth.sign.up.sent.email.subtitle": "创建您的账号", "com.affine.auth.sign.up.success.subtitle": "AFFiNE 客户端将自动打开或重定向到网页端,如果您遇到任何问题,可以点击下方按钮手动打开 AFFiNE。", diff --git a/packages/frontend/i18n/src/resources/zh-Hant.json b/packages/frontend/i18n/src/resources/zh-Hant.json index 32e6b38a3..e69f3064f 100644 --- a/packages/frontend/i18n/src/resources/zh-Hant.json +++ b/packages/frontend/i18n/src/resources/zh-Hant.json @@ -365,7 +365,7 @@ "com.affine.auth.sign.message": "點擊上方「使用 Google/電子郵件地址 繼續」,即表示您確認同意 AFFiNE 的 <1>Terms of Conditions and <3>Privacy Policy。", "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": "一封帶有魔法連結的電子郵件已發送至 {{email}}。", "com.affine.auth.sign.up": "建立帳號", "com.affine.auth.sign.up.sent.email.subtitle": "建立您的帳號", "com.affine.auth.sign.up.success.subtitle": "應用將自動打開或重定向到網頁版本。如果您遇到任何問題,您還可以點擊下面的按鈕手動打開 AFFiNE 應用程序。", diff --git a/tests/kit/utils/cloud.ts b/tests/kit/utils/cloud.ts index 0fe780780..7a54d1e91 100644 --- a/tests/kit/utils/cloud.ts +++ b/tests/kit/utils/cloud.ts @@ -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();