fix: can not enable workspace if not sign in (#4265)

Co-authored-by: Alex Yang <himself65@outlook.com>
This commit is contained in:
Qi
2023-09-08 15:41:07 +08:00
committed by GitHub
parent 81a3bcee4f
commit f9eea85577
9 changed files with 102 additions and 38 deletions

View File

@@ -0,0 +1,25 @@
import { atom, useAtom } from 'jotai';
import { useCallback } from 'react';
export type OnceSignedInEvent = () => void;
export const onceSignedInEventsAtom = atom<OnceSignedInEvent[]>([]);
export const setOnceSignedInEventAtom = atom(
null,
(get, set, event: OnceSignedInEvent) => {
set(onceSignedInEventsAtom, [...get(onceSignedInEventsAtom), event]);
}
);
export const useOnceSignedInEvents = () => {
const [events, setEvents] = useAtom(onceSignedInEventsAtom);
return useCallback(async () => {
try {
await Promise.all(events.map(event => event()));
} catch (err) {
console.error('Error executing one of the events:', err);
}
setEvents([]);
}, [events, setEvents]);
};

View File

@@ -27,8 +27,6 @@ export type AuthAtom = {
state: AuthProps['state'];
email?: string;
emailType?: AuthProps['emailType'];
// Only used for sign in page callback, after called, it will be set to undefined
onceSignedIn?: () => void;
};
export const authAtom = atom<AuthAtom>({

View File

@@ -2,7 +2,12 @@ import { Modal, ModalWrapper } from '@affine/component';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { CloseIcon } from '@blocksuite/icons';
import { Button, IconButton } from '@toeverything/components/button';
import { useSetAtom } from 'jotai';
import { useCallback } from 'react';
import { authAtom } from '../../../atoms';
import { setOnceSignedInEventAtom } from '../../../atoms/event';
import { useCurrentLoginStatus } from '../../../hooks/affine/use-current-login-status';
import { ButtonContainer, Content, Header, StyleTips, Title } from './style';
interface EnableAffineCloudModalProps {
@@ -12,11 +17,31 @@ interface EnableAffineCloudModalProps {
}
export const EnableAffineCloudModal = ({
onConfirm,
onConfirm: propsOnConfirm,
open,
onClose,
}: EnableAffineCloudModalProps) => {
const t = useAFFiNEI18N();
const loginStatus = useCurrentLoginStatus();
const setAuthAtom = useSetAtom(authAtom);
const setOnceSignedInEvent = useSetAtom(setOnceSignedInEventAtom);
const confirm = useCallback(async () => {
return propsOnConfirm();
}, [propsOnConfirm]);
const onConfirm = useCallback(() => {
if (loginStatus === 'unauthenticated') {
setAuthAtom(prev => ({
...prev,
openModal: true,
}));
setOnceSignedInEvent(confirm);
}
if (loginStatus === 'authenticated') {
return propsOnConfirm();
}
}, [confirm, loginStatus, propsOnConfirm, setAuthAtom, setOnceSignedInEvent]);
return (
<Modal open={open} onClose={onClose} data-testid="logout-modal">
@@ -42,7 +67,9 @@ export const EnableAffineCloudModal = ({
block
onClick={onConfirm}
>
{t['Sign in and Enable']()}
{loginStatus === 'authenticated'
? t['Enable']()
: t['Sign in and Enable']()}
</Button>
</div>
</ButtonContainer>

View File

@@ -1,6 +1,8 @@
import { pushNotificationAtom } from '@affine/component/notification-center';
import type { WorkspaceRegistry } from '@affine/env/workspace';
import type { WorkspaceFlavour } from '@affine/env/workspace';
import { WorkspaceSubPath } from '@affine/env/workspace';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import {
rootWorkspacesMetadataAtom,
workspaceAdaptersAtom,
@@ -14,11 +16,14 @@ import { openSettingModalAtom } from '../../atoms';
import { useNavigateHelper } from '../use-navigate-helper';
export function useOnTransformWorkspace() {
const t = useAFFiNEI18N();
const setSettingModal = useSetAtom(openSettingModalAtom);
const WorkspaceAdapters = useAtomValue(workspaceAdaptersAtom);
const setMetadata = useSetAtom(rootWorkspacesMetadataAtom);
const { openPage } = useNavigateHelper();
const currentPageId = useAtomValue(currentPageIdAtom);
const pushNotification = useSetAtom(pushNotificationAtom);
return useCallback(
async <From extends WorkspaceFlavour, To extends WorkspaceFlavour>(
from: From,
@@ -55,8 +60,20 @@ export function useOnTransformWorkspace() {
})
);
openPage(newId, currentPageId ?? WorkspaceSubPath.ALL);
pushNotification({
title: t['Successfully enabled AFFiNE Cloud'](),
type: 'success',
});
},
[WorkspaceAdapters, setMetadata, setSettingModal, openPage, currentPageId]
[
WorkspaceAdapters,
setMetadata,
setSettingModal,
openPage,
currentPageId,
pushNotification,
t,
]
);
}

View File

@@ -6,11 +6,12 @@ import {
getInviteInfoQuery,
} from '@affine/graphql';
import { fetcher } from '@affine/workspace/affine/gql';
import { useAtom } from 'jotai';
import { useSetAtom } from 'jotai';
import { useCallback, useEffect } from 'react';
import { type LoaderFunction, redirect, useLoaderData } from 'react-router-dom';
import { authAtom } from '../atoms';
import { setOnceSignedInEventAtom } from '../atoms/event';
import { useCurrentLoginStatus } from '../hooks/affine/use-current-login-status';
import { RouteLogic, useNavigateHelper } from '../hooks/use-navigate-helper';
import { useAppHelper } from '../hooks/use-workspaces';
@@ -51,16 +52,14 @@ export const Component = () => {
const { addCloudWorkspace } = useAppHelper();
const { jumpToSubPath } = useNavigateHelper();
const [, setAuthAtom] = useAtom(authAtom);
const setOnceSignedInEvent = useSetAtom(setOnceSignedInEventAtom);
const setAuthAtom = useSetAtom(authAtom);
const { inviteInfo } = useLoaderData() as {
inviteId: string;
inviteInfo: GetInviteInfoQuery['getInviteInfo'];
};
const loadWorkspaceAfterSignIn = useCallback(() => {
addCloudWorkspace(inviteInfo.workspace.id);
}, [addCloudWorkspace, inviteInfo.workspace.id]);
const openWorkspace = useCallback(() => {
addCloudWorkspace(inviteInfo.workspace.id);
jumpToSubPath(
@@ -73,10 +72,7 @@ export const Component = () => {
useEffect(() => {
if (loginStatus === 'unauthenticated') {
// We can not pass function to navigate state, so we need to save it in atom
setAuthAtom(prev => ({
...prev,
onceSignedIn: loadWorkspaceAfterSignIn,
}));
setOnceSignedInEvent(openWorkspace);
jumpToSignIn(RouteLogic.REPLACE, {
state: {
callbackURL: `/workspace/${inviteInfo.workspace.id}/all`,
@@ -86,9 +82,10 @@ export const Component = () => {
}, [
inviteInfo.workspace.id,
jumpToSignIn,
loadWorkspaceAfterSignIn,
loginStatus,
openWorkspace,
setAuthAtom,
setOnceSignedInEvent,
]);
if (loginStatus === 'authenticated') {

View File

@@ -7,6 +7,7 @@ import { useLocation, useNavigate } from 'react-router-dom';
import { authAtom } from '../atoms';
import { AuthPanel } from '../components/affine/auth';
import { useCurrentLoginStatus } from '../hooks/affine/use-current-login-status';
import { RouteLogic, useNavigateHelper } from '../hooks/use-navigate-helper';
interface LocationState {
state?: {
@@ -14,36 +15,28 @@ interface LocationState {
};
}
export const Component = () => {
const [
{ state, email = '', emailType = 'changePassword', onceSignedIn },
setAuthAtom,
] = useAtom(authAtom);
const [{ state, email = '', emailType = 'changePassword' }, setAuthAtom] =
useAtom(authAtom);
const loginStatus = useCurrentLoginStatus();
const location = useLocation() as LocationState;
const navigate = useNavigate();
const { jumpToIndex } = useNavigateHelper();
useEffect(() => {
const afterSignedIn = async () => {
if (loginStatus === 'authenticated') {
if (onceSignedIn) {
await onceSignedIn();
setAuthAtom(prev => ({ ...prev, onceSignedIn: undefined }));
}
if (location.state?.callbackURL) {
navigate(location.state.callbackURL, {
replace: true,
});
}
if (loginStatus === 'authenticated') {
if (location.state?.callbackURL) {
navigate(location.state.callbackURL, {
replace: true,
});
} else {
jumpToIndex(RouteLogic.REPLACE);
}
};
afterSignedIn().catch(err => {
console.error(err);
});
}
}, [
jumpToIndex,
location.state?.callbackURL,
loginStatus,
navigate,
onceSignedIn,
setAuthAtom,
]);

View File

@@ -101,6 +101,7 @@ export const AuthModal = (): ReactElement => {
{ openModal, state, email = '', emailType = 'changePassword' },
setAuthAtom,
] = useAtom(authAtom);
return (
<Auth
open={openModal}

View File

@@ -9,11 +9,14 @@ import { useSetAtom } from 'jotai';
import { SessionProvider, useSession } from 'next-auth/react';
import { type PropsWithChildren, startTransition, useRef } from 'react';
import { useOnceSignedInEvents } from '../atoms/event';
const SessionReporter = () => {
const session = useSession();
const prevSession = useRef<ReturnType<typeof useSession>>();
const pushNotification = useSetAtom(pushNotificationAtom);
const refreshMetadata = useSetAtom(refreshRootMetadataAtom);
const onceSignedInEvents = useOnceSignedInEvents();
const t = useAFFiNEI18N();
if (prevSession.current !== session && session.status !== 'loading') {
@@ -23,7 +26,9 @@ const SessionReporter = () => {
session.status === 'authenticated'
) {
startTransition(() => {
refreshMetadata();
onceSignedInEvents().then(() => {
refreshMetadata();
});
});
pushNotification({
title: t['com.affine.auth.has.signed'](),