mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-19 02:56:23 +08:00
refactor(auth): authenticate user in main window (#8032)
This commit is contained in:
@@ -9,7 +9,7 @@ import { Button } from '@affine/component/ui/button';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { AuthService } from '@affine/core/modules/cloud';
|
||||
import { Trans, useI18n } from '@affine/i18n';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import { useService } from '@toeverything/infra';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
import type { AuthPanelProps } from './index';
|
||||
@@ -17,10 +17,9 @@ import * as style from './style.css';
|
||||
import { Captcha, useCaptcha } from './use-captcha';
|
||||
|
||||
export const AfterSignInSendEmail = ({
|
||||
setAuthState,
|
||||
setAuthData: setAuth,
|
||||
email,
|
||||
onSignedIn,
|
||||
}: AuthPanelProps) => {
|
||||
}: AuthPanelProps<'afterSignInSendEmail'>) => {
|
||||
const [resendCountDown, setResendCountDown] = useState(60);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -37,22 +36,9 @@ export const AfterSignInSendEmail = ({
|
||||
|
||||
const t = useI18n();
|
||||
const authService = useService(AuthService);
|
||||
useEffect(() => {
|
||||
const timer = setInterval(() => {
|
||||
authService.session.revalidate();
|
||||
}, 3000);
|
||||
|
||||
return () => {
|
||||
clearInterval(timer);
|
||||
};
|
||||
}, [authService]);
|
||||
const loginStatus = useLiveData(authService.session.status$);
|
||||
const [verifyToken, challenge] = useCaptcha();
|
||||
|
||||
if (loginStatus === 'authenticated') {
|
||||
onSignedIn?.();
|
||||
}
|
||||
|
||||
const onResendClick = useAsyncCallback(async () => {
|
||||
setIsSending(true);
|
||||
try {
|
||||
@@ -70,12 +56,12 @@ export const AfterSignInSendEmail = ({
|
||||
}, [authService, challenge, email, verifyToken]);
|
||||
|
||||
const onSignInWithPasswordClick = useCallback(() => {
|
||||
setAuthState('signInWithPassword');
|
||||
}, [setAuthState]);
|
||||
setAuth({ state: 'signInWithPassword' });
|
||||
}, [setAuth]);
|
||||
|
||||
const onBackBottomClick = useCallback(() => {
|
||||
setAuthState('signIn');
|
||||
}, [setAuthState]);
|
||||
setAuth({ state: 'signIn' });
|
||||
}, [setAuth]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
import { Button } from '@affine/component/ui/button';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { Trans, useI18n } from '@affine/i18n';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import { useService } from '@toeverything/infra';
|
||||
import type { FC } from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
@@ -17,11 +17,9 @@ import type { AuthPanelProps } from './index';
|
||||
import * as style from './style.css';
|
||||
import { Captcha, useCaptcha } from './use-captcha';
|
||||
|
||||
export const AfterSignUpSendEmail: FC<AuthPanelProps> = ({
|
||||
setAuthState,
|
||||
email,
|
||||
onSignedIn,
|
||||
}) => {
|
||||
export const AfterSignUpSendEmail: FC<
|
||||
AuthPanelProps<'afterSignUpSendEmail'>
|
||||
> = ({ setAuthData, email }) => {
|
||||
const [resendCountDown, setResendCountDown] = useState(60);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -37,19 +35,6 @@ export const AfterSignUpSendEmail: FC<AuthPanelProps> = ({
|
||||
const [isSending, setIsSending] = useState(false);
|
||||
const t = useI18n();
|
||||
const authService = useService(AuthService);
|
||||
const loginStatus = useLiveData(authService.session.status$);
|
||||
useEffect(() => {
|
||||
const timeout = setInterval(() => {
|
||||
// revalidate session to get the latest status
|
||||
authService.session.revalidate();
|
||||
}, 3000);
|
||||
return () => {
|
||||
clearInterval(timeout);
|
||||
};
|
||||
}, [authService]);
|
||||
if (loginStatus === 'authenticated') {
|
||||
onSignedIn?.();
|
||||
}
|
||||
|
||||
const [verifyToken, challenge] = useCaptcha();
|
||||
|
||||
@@ -117,8 +102,8 @@ export const AfterSignUpSendEmail: FC<AuthPanelProps> = ({
|
||||
|
||||
<BackButton
|
||||
onClick={useCallback(() => {
|
||||
setAuthState('signIn');
|
||||
}, [setAuthState])}
|
||||
setAuthData({ state: 'signIn' });
|
||||
}, [setAuthData])}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
import type { AuthModalProps as AuthModalBaseProps } from '@affine/component/auth-components';
|
||||
import { notify } from '@affine/component';
|
||||
import { AuthModal as AuthModalBase } from '@affine/component/auth-components';
|
||||
import { authAtom, type AuthAtomData } from '@affine/core/atoms';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { AuthService } from '@affine/core/modules/cloud';
|
||||
import { apis, events } from '@affine/electron-api';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import { useAtom } from 'jotai/react';
|
||||
import type { FC } from 'react';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useCallback, useEffect, useRef } from 'react';
|
||||
|
||||
import { AfterSignInSendEmail } from './after-sign-in-send-email';
|
||||
import { AfterSignUpSendEmail } from './after-sign-up-send-email';
|
||||
@@ -9,33 +16,25 @@ import { SendEmail } from './send-email';
|
||||
import { SignIn } from './sign-in';
|
||||
import { SignInWithPassword } from './sign-in-with-password';
|
||||
|
||||
export type AuthProps = {
|
||||
state:
|
||||
| 'signIn'
|
||||
| 'afterSignUpSendEmail'
|
||||
| 'afterSignInSendEmail'
|
||||
// throw away
|
||||
| 'signInWithPassword'
|
||||
| 'sendEmail';
|
||||
setAuthState: (state: AuthProps['state']) => void;
|
||||
setAuthEmail: (state: AuthProps['email']) => void;
|
||||
setEmailType: (state: AuthProps['emailType']) => void;
|
||||
email: string;
|
||||
emailType: 'setPassword' | 'changePassword' | 'changeEmail' | 'verifyEmail';
|
||||
onSignedIn?: () => void;
|
||||
};
|
||||
type AuthAtomType<T extends AuthAtomData['state']> = Extract<
|
||||
AuthAtomData,
|
||||
{ state: T }
|
||||
>;
|
||||
|
||||
export type AuthPanelProps = {
|
||||
email: string;
|
||||
setAuthState: AuthProps['setAuthState'];
|
||||
setAuthEmail: AuthProps['setAuthEmail'];
|
||||
setEmailType: AuthProps['setEmailType'];
|
||||
emailType: AuthProps['emailType'];
|
||||
onSignedIn?: () => void;
|
||||
};
|
||||
// return field in B that is not in A
|
||||
type Difference<
|
||||
A extends Record<string, any>,
|
||||
B extends Record<string, any>,
|
||||
> = Pick<B, Exclude<keyof B, keyof A>>;
|
||||
|
||||
export type AuthPanelProps<State extends AuthAtomData['state']> = {
|
||||
setAuthData: <T extends AuthAtomData['state']>(
|
||||
updates: { state: T } & Difference<AuthAtomType<State>, AuthAtomType<T>>
|
||||
) => void;
|
||||
} & Extract<AuthAtomData, { state: State }>;
|
||||
|
||||
const config: {
|
||||
[k in AuthProps['state']]: FC<AuthPanelProps>;
|
||||
[k in AuthAtomData['state']]: FC<AuthPanelProps<k>>;
|
||||
} = {
|
||||
signIn: SignIn,
|
||||
afterSignUpSendEmail: AfterSignUpSendEmail,
|
||||
@@ -44,58 +43,100 @@ const config: {
|
||||
sendEmail: SendEmail,
|
||||
};
|
||||
|
||||
export const AuthModal: FC<AuthModalBaseProps & AuthProps> = ({
|
||||
open,
|
||||
state,
|
||||
setOpen,
|
||||
email,
|
||||
setAuthEmail,
|
||||
setAuthState,
|
||||
setEmailType,
|
||||
emailType,
|
||||
}) => {
|
||||
const onSignedIn = useCallback(() => {
|
||||
setAuthState('signIn');
|
||||
setAuthEmail('');
|
||||
setOpen(false);
|
||||
}, [setAuthState, setAuthEmail, setOpen]);
|
||||
export function AuthModal() {
|
||||
const t = useI18n();
|
||||
const [authAtomValue, setAuthAtom] = useAtom(authAtom);
|
||||
const authService = useService(AuthService);
|
||||
const setOpen = useCallback(
|
||||
(open: boolean) => {
|
||||
setAuthAtom(prev => ({ ...prev, openModal: open }));
|
||||
},
|
||||
[setAuthAtom]
|
||||
);
|
||||
|
||||
const signIn = useAsyncCallback(
|
||||
async ({
|
||||
method,
|
||||
payload,
|
||||
}: {
|
||||
method: 'magic-link' | 'oauth';
|
||||
payload: any;
|
||||
}) => {
|
||||
if (!(await apis?.ui.isActiveTab())) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
switch (method) {
|
||||
case 'magic-link': {
|
||||
const { email, token } = payload;
|
||||
await authService.signInMagicLink(email, token);
|
||||
break;
|
||||
}
|
||||
case 'oauth': {
|
||||
const { code, state } = payload;
|
||||
await authService.signInOauth(code, state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
authService.session.revalidate();
|
||||
} catch (e) {
|
||||
notify.error({
|
||||
title: t['com.affine.auth.toast.title.failed'](),
|
||||
message: (e as any).message,
|
||||
});
|
||||
}
|
||||
},
|
||||
[authService, t]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
return events?.ui.onAuthenticationRequest(signIn);
|
||||
}, [signIn]);
|
||||
|
||||
return (
|
||||
<AuthModalBase open={open} setOpen={setOpen}>
|
||||
<AuthPanel
|
||||
state={state}
|
||||
email={email}
|
||||
setAuthEmail={setAuthEmail}
|
||||
setAuthState={setAuthState}
|
||||
setEmailType={setEmailType}
|
||||
emailType={emailType}
|
||||
onSignedIn={onSignedIn}
|
||||
/>
|
||||
<AuthModalBase open={authAtomValue.openModal} setOpen={setOpen}>
|
||||
<AuthPanel />
|
||||
</AuthModalBase>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export const AuthPanel: FC<AuthProps> = ({
|
||||
state,
|
||||
email,
|
||||
setAuthEmail,
|
||||
setAuthState,
|
||||
setEmailType,
|
||||
emailType,
|
||||
onSignedIn,
|
||||
}) => {
|
||||
const CurrentPanel = useMemo(() => {
|
||||
return config[state];
|
||||
}, [state]);
|
||||
export function AuthPanel() {
|
||||
const t = useI18n();
|
||||
const [authAtomValue, setAuthAtom] = useAtom(authAtom);
|
||||
const authService = useService(AuthService);
|
||||
const loginStatus = useLiveData(authService.session.status$);
|
||||
const previousLoginStatus = useRef(loginStatus);
|
||||
|
||||
return (
|
||||
<CurrentPanel
|
||||
email={email}
|
||||
setAuthState={setAuthState}
|
||||
setAuthEmail={setAuthEmail}
|
||||
setEmailType={setEmailType}
|
||||
emailType={emailType}
|
||||
onSignedIn={onSignedIn}
|
||||
/>
|
||||
const setAuthData = useCallback(
|
||||
(updates: Partial<AuthAtomData>) => {
|
||||
// @ts-expect-error checked in impls
|
||||
setAuthAtom(prev => ({
|
||||
...prev,
|
||||
...updates,
|
||||
}));
|
||||
},
|
||||
[setAuthAtom]
|
||||
);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
loginStatus === 'authenticated' &&
|
||||
previousLoginStatus.current === 'unauthenticated'
|
||||
) {
|
||||
setAuthAtom({
|
||||
openModal: false,
|
||||
state: 'signIn',
|
||||
});
|
||||
notify.success({
|
||||
title: t['com.affine.auth.toast.title.signed-in'](),
|
||||
message: t['com.affine.auth.toast.message.signed-in'](),
|
||||
});
|
||||
}
|
||||
previousLoginStatus.current = loginStatus;
|
||||
}, [loginStatus, setAuthAtom, t]);
|
||||
|
||||
const CurrentPanel = config[authAtomValue.state];
|
||||
|
||||
// @ts-expect-error checked in impls
|
||||
return <CurrentPanel {...authAtomValue} setAuthData={setAuthData} />;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ import { notify, Skeleton } from '@affine/component';
|
||||
import { Button } from '@affine/component/ui/button';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { track } from '@affine/core/mixpanel';
|
||||
import { popupWindow } from '@affine/core/utils';
|
||||
import { apis } from '@affine/electron-api';
|
||||
import { OAuthProviderType } from '@affine/graphql';
|
||||
import { GithubIcon, GoogleDuotoneIcon } from '@blocksuite/icons/rc';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
@@ -59,7 +61,12 @@ function OAuthProvider({ provider }: { provider: OAuthProviderType }) {
|
||||
const onClick = useAsyncCallback(async () => {
|
||||
try {
|
||||
setIsConnecting(true);
|
||||
await authService.signInOauth(provider);
|
||||
const url = await authService.oauthPreflight(provider);
|
||||
if (environment.isDesktop) {
|
||||
await apis?.ui.openExternal(url);
|
||||
} else {
|
||||
popupWindow(url);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
notify.error({ title: 'Failed to sign in, please try again.' });
|
||||
|
||||
@@ -21,7 +21,7 @@ import { useMutation } from '../../../hooks/use-mutation';
|
||||
import { ServerConfigService } from '../../../modules/cloud';
|
||||
import type { AuthPanelProps } from './index';
|
||||
|
||||
const useEmailTitle = (emailType: AuthPanelProps['emailType']) => {
|
||||
const useEmailTitle = (emailType: AuthPanelProps<'sendEmail'>['emailType']) => {
|
||||
const t = useI18n();
|
||||
|
||||
switch (emailType) {
|
||||
@@ -36,7 +36,9 @@ const useEmailTitle = (emailType: AuthPanelProps['emailType']) => {
|
||||
}
|
||||
};
|
||||
|
||||
const useNotificationHint = (emailType: AuthPanelProps['emailType']) => {
|
||||
const useNotificationHint = (
|
||||
emailType: AuthPanelProps<'sendEmail'>['emailType']
|
||||
) => {
|
||||
const t = useI18n();
|
||||
|
||||
switch (emailType) {
|
||||
@@ -49,7 +51,9 @@ const useNotificationHint = (emailType: AuthPanelProps['emailType']) => {
|
||||
return t['com.affine.auth.sent.verify.email.hint']();
|
||||
}
|
||||
};
|
||||
const useButtonContent = (emailType: AuthPanelProps['emailType']) => {
|
||||
const useButtonContent = (
|
||||
emailType: AuthPanelProps<'sendEmail'>['emailType']
|
||||
) => {
|
||||
const t = useI18n();
|
||||
|
||||
switch (emailType) {
|
||||
@@ -63,7 +67,7 @@ const useButtonContent = (emailType: AuthPanelProps['emailType']) => {
|
||||
}
|
||||
};
|
||||
|
||||
const useSendEmail = (emailType: AuthPanelProps['emailType']) => {
|
||||
const useSendEmail = (emailType: AuthPanelProps<'sendEmail'>['emailType']) => {
|
||||
const {
|
||||
trigger: sendChangePasswordEmail,
|
||||
isMutating: isChangePasswordMutating,
|
||||
@@ -134,10 +138,10 @@ const useSendEmail = (emailType: AuthPanelProps['emailType']) => {
|
||||
};
|
||||
|
||||
export const SendEmail = ({
|
||||
setAuthState,
|
||||
setAuthData,
|
||||
email,
|
||||
emailType,
|
||||
}: AuthPanelProps) => {
|
||||
}: AuthPanelProps<'sendEmail'>) => {
|
||||
const t = useI18n();
|
||||
const serverConfig = useService(ServerConfigService).serverConfig;
|
||||
|
||||
@@ -160,8 +164,8 @@ export const SendEmail = ({
|
||||
}, [email, hint, sendEmail]);
|
||||
|
||||
const onBack = useCallback(() => {
|
||||
setAuthState('signIn');
|
||||
}, [setAuthState]);
|
||||
setAuthData({ state: 'signIn' });
|
||||
}, [setAuthData]);
|
||||
|
||||
if (!passwordLimits) {
|
||||
// TODO(@eyhn): loading & error UI
|
||||
|
||||
@@ -16,11 +16,9 @@ import type { AuthPanelProps } from './index';
|
||||
import * as styles from './style.css';
|
||||
import { useCaptcha } from './use-captcha';
|
||||
|
||||
export const SignInWithPassword: FC<AuthPanelProps> = ({
|
||||
setAuthState,
|
||||
setEmailType,
|
||||
export const SignInWithPassword: FC<AuthPanelProps<'signInWithPassword'>> = ({
|
||||
setAuthData,
|
||||
email,
|
||||
onSignedIn,
|
||||
}) => {
|
||||
const t = useI18n();
|
||||
const authService = useService(AuthService);
|
||||
@@ -40,14 +38,13 @@ export const SignInWithPassword: FC<AuthPanelProps> = ({
|
||||
email,
|
||||
password,
|
||||
});
|
||||
onSignedIn?.();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
setPasswordError(true);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [isLoading, authService, email, password, onSignedIn]);
|
||||
}, [isLoading, authService, email, password]);
|
||||
|
||||
const sendMagicLink = useAsyncCallback(async () => {
|
||||
if (sendingEmail) return;
|
||||
@@ -55,7 +52,7 @@ export const SignInWithPassword: FC<AuthPanelProps> = ({
|
||||
try {
|
||||
if (verifyToken) {
|
||||
await authService.sendEmailMagicLink(email, verifyToken, challenge);
|
||||
setAuthState('afterSignInSendEmail');
|
||||
setAuthData({ state: 'afterSignInSendEmail' });
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
@@ -65,12 +62,11 @@ export const SignInWithPassword: FC<AuthPanelProps> = ({
|
||||
// TODO(@eyhn): handle error better
|
||||
}
|
||||
setSendingEmail(false);
|
||||
}, [sendingEmail, verifyToken, authService, email, challenge, setAuthState]);
|
||||
}, [sendingEmail, verifyToken, authService, email, challenge, setAuthData]);
|
||||
|
||||
const sendChangePasswordEmail = useCallback(() => {
|
||||
setEmailType('changePassword');
|
||||
setAuthState('sendEmail');
|
||||
}, [setAuthState, setEmailType]);
|
||||
setAuthData({ state: 'sendEmail', emailType: 'changePassword' });
|
||||
}, [setAuthData]);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -140,8 +136,8 @@ export const SignInWithPassword: FC<AuthPanelProps> = ({
|
||||
</Wrapper>
|
||||
<BackButton
|
||||
onClick={useCallback(() => {
|
||||
setAuthState('signIn');
|
||||
}, [setAuthState])}
|
||||
setAuthData({ state: 'signIn' });
|
||||
}, [setAuthData])}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
import { notify } from '@affine/component';
|
||||
import { AuthInput, ModalHeader } from '@affine/component/auth-components';
|
||||
import { Button } from '@affine/component/ui/button';
|
||||
import { authAtom } from '@affine/core/atoms';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { track } from '@affine/core/mixpanel';
|
||||
import { Trans, useI18n } from '@affine/i18n';
|
||||
import { ArrowRightBigIcon } from '@blocksuite/icons/rc';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import { useService } from '@toeverything/infra';
|
||||
import { cssVar } from '@toeverything/theme';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import type { FC } from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
|
||||
import { AuthService } from '../../../modules/cloud';
|
||||
@@ -24,36 +22,19 @@ function validateEmail(email: string) {
|
||||
return emailRegex.test(email);
|
||||
}
|
||||
|
||||
export const SignIn: FC<AuthPanelProps> = ({
|
||||
setAuthState,
|
||||
setAuthEmail,
|
||||
email,
|
||||
onSignedIn,
|
||||
export const SignIn: FC<AuthPanelProps<'signIn'>> = ({
|
||||
setAuthData: setAuthState,
|
||||
}) => {
|
||||
const t = useI18n();
|
||||
const authService = useService(AuthService);
|
||||
const [searchParams] = useSearchParams();
|
||||
const [isMutating, setIsMutating] = useState(false);
|
||||
const [verifyToken, challenge] = useCaptcha();
|
||||
const [email, setEmail] = useState('');
|
||||
|
||||
const [isValidEmail, setIsValidEmail] = useState(true);
|
||||
const { openModal } = useAtomValue(authAtom);
|
||||
const errorMsg = searchParams.get('error');
|
||||
|
||||
useEffect(() => {
|
||||
const timeout = setInterval(() => {
|
||||
// revalidate session to get the latest status
|
||||
authService.session.revalidate();
|
||||
}, 3000);
|
||||
return () => {
|
||||
clearInterval(timeout);
|
||||
};
|
||||
}, [authService]);
|
||||
const loginStatus = useLiveData(authService.session.status$);
|
||||
if (loginStatus === 'authenticated' && openModal) {
|
||||
onSignedIn?.();
|
||||
}
|
||||
|
||||
const onContinue = useAsyncCallback(async () => {
|
||||
if (!validateEmail(email)) {
|
||||
setIsValidEmail(false);
|
||||
@@ -61,10 +42,8 @@ export const SignIn: FC<AuthPanelProps> = ({
|
||||
}
|
||||
|
||||
setIsValidEmail(true);
|
||||
|
||||
setIsMutating(true);
|
||||
|
||||
setAuthEmail(email);
|
||||
try {
|
||||
const { hasPassword, registered } =
|
||||
await authService.checkUserByEmail(email);
|
||||
@@ -74,16 +53,25 @@ export const SignIn: FC<AuthPanelProps> = ({
|
||||
// provider password sign-in if user has by default
|
||||
// If with payment, onl support email sign in to avoid redirect to affine app
|
||||
if (hasPassword) {
|
||||
setAuthState('signInWithPassword');
|
||||
setAuthState({
|
||||
state: 'signInWithPassword',
|
||||
email,
|
||||
});
|
||||
} else {
|
||||
track.$.$.auth.signIn();
|
||||
await authService.sendEmailMagicLink(email, verifyToken, challenge);
|
||||
setAuthState('afterSignInSendEmail');
|
||||
setAuthState({
|
||||
state: 'afterSignInSendEmail',
|
||||
email,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
await authService.sendEmailMagicLink(email, verifyToken, challenge);
|
||||
track.$.$.auth.signUp();
|
||||
setAuthState('afterSignUpSendEmail');
|
||||
setAuthState({
|
||||
state: 'afterSignUpSendEmail',
|
||||
email,
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -96,7 +84,7 @@ export const SignIn: FC<AuthPanelProps> = ({
|
||||
}
|
||||
|
||||
setIsMutating(false);
|
||||
}, [authService, challenge, email, setAuthEmail, setAuthState, verifyToken]);
|
||||
}, [authService, challenge, email, setAuthState, verifyToken]);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -111,13 +99,7 @@ export const SignIn: FC<AuthPanelProps> = ({
|
||||
<AuthInput
|
||||
label={t['com.affine.settings.email']()}
|
||||
placeholder={t['com.affine.auth.sign.email.placeholder']()}
|
||||
value={email}
|
||||
onChange={useCallback(
|
||||
(value: string) => {
|
||||
setAuthEmail(value);
|
||||
},
|
||||
[setAuthEmail]
|
||||
)}
|
||||
onChange={setEmail}
|
||||
error={!isValidEmail}
|
||||
errorHint={
|
||||
isValidEmail ? '' : t['com.affine.auth.sign.email.error']()
|
||||
|
||||
@@ -195,6 +195,7 @@ export const AccountSetting: FC = () => {
|
||||
setAuthModal({
|
||||
openModal: true,
|
||||
state: 'sendEmail',
|
||||
// @ts-expect-error accont email is always defined
|
||||
email: account.email,
|
||||
emailType: account.info?.emailVerified ? 'changeEmail' : 'verifyEmail',
|
||||
});
|
||||
@@ -204,6 +205,7 @@ export const AccountSetting: FC = () => {
|
||||
setAuthModal({
|
||||
openModal: true,
|
||||
state: 'sendEmail',
|
||||
// @ts-expect-error accont email is always defined
|
||||
email: account.email,
|
||||
emailType: account.info?.hasPassword ? 'changePassword' : 'setPassword',
|
||||
});
|
||||
|
||||
+2
-2
@@ -21,7 +21,7 @@ import {
|
||||
WorkspacesService,
|
||||
} from '@toeverything/infra';
|
||||
import clsx from 'clsx';
|
||||
import { useAtom } from 'jotai/react';
|
||||
import { useSetAtom } from 'jotai/react';
|
||||
import {
|
||||
type MouseEvent,
|
||||
Suspense,
|
||||
@@ -81,7 +81,7 @@ export const UserInfo = ({ onAccountSettingClick, active }: UserInfoProps) => {
|
||||
|
||||
export const SignInButton = () => {
|
||||
const t = useI18n();
|
||||
const [, setAuthModal] = useAtom(authAtom);
|
||||
const setAuthModal = useSetAtom(authAtom);
|
||||
|
||||
return (
|
||||
<div
|
||||
|
||||
Reference in New Issue
Block a user