fix: can not enable workspace if not sign in (#4265)
Co-authored-by: Alex Yang <himself65@outlook.com>
This commit is contained in:
25
apps/core/src/atoms/event.ts
Normal file
25
apps/core/src/atoms/event.ts
Normal 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]);
|
||||||
|
};
|
||||||
@@ -27,8 +27,6 @@ export type AuthAtom = {
|
|||||||
state: AuthProps['state'];
|
state: AuthProps['state'];
|
||||||
email?: string;
|
email?: string;
|
||||||
emailType?: AuthProps['emailType'];
|
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>({
|
export const authAtom = atom<AuthAtom>({
|
||||||
|
|||||||
@@ -2,7 +2,12 @@ import { Modal, ModalWrapper } from '@affine/component';
|
|||||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||||
import { CloseIcon } from '@blocksuite/icons';
|
import { CloseIcon } from '@blocksuite/icons';
|
||||||
import { Button, IconButton } from '@toeverything/components/button';
|
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';
|
import { ButtonContainer, Content, Header, StyleTips, Title } from './style';
|
||||||
|
|
||||||
interface EnableAffineCloudModalProps {
|
interface EnableAffineCloudModalProps {
|
||||||
@@ -12,11 +17,31 @@ interface EnableAffineCloudModalProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const EnableAffineCloudModal = ({
|
export const EnableAffineCloudModal = ({
|
||||||
onConfirm,
|
onConfirm: propsOnConfirm,
|
||||||
open,
|
open,
|
||||||
onClose,
|
onClose,
|
||||||
}: EnableAffineCloudModalProps) => {
|
}: EnableAffineCloudModalProps) => {
|
||||||
const t = useAFFiNEI18N();
|
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 (
|
return (
|
||||||
<Modal open={open} onClose={onClose} data-testid="logout-modal">
|
<Modal open={open} onClose={onClose} data-testid="logout-modal">
|
||||||
@@ -42,7 +67,9 @@ export const EnableAffineCloudModal = ({
|
|||||||
block
|
block
|
||||||
onClick={onConfirm}
|
onClick={onConfirm}
|
||||||
>
|
>
|
||||||
{t['Sign in and Enable']()}
|
{loginStatus === 'authenticated'
|
||||||
|
? t['Enable']()
|
||||||
|
: t['Sign in and Enable']()}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</ButtonContainer>
|
</ButtonContainer>
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
import { pushNotificationAtom } from '@affine/component/notification-center';
|
||||||
import type { WorkspaceRegistry } from '@affine/env/workspace';
|
import type { WorkspaceRegistry } from '@affine/env/workspace';
|
||||||
import type { WorkspaceFlavour } from '@affine/env/workspace';
|
import type { WorkspaceFlavour } from '@affine/env/workspace';
|
||||||
import { WorkspaceSubPath } from '@affine/env/workspace';
|
import { WorkspaceSubPath } from '@affine/env/workspace';
|
||||||
|
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||||
import {
|
import {
|
||||||
rootWorkspacesMetadataAtom,
|
rootWorkspacesMetadataAtom,
|
||||||
workspaceAdaptersAtom,
|
workspaceAdaptersAtom,
|
||||||
@@ -14,11 +16,14 @@ import { openSettingModalAtom } from '../../atoms';
|
|||||||
import { useNavigateHelper } from '../use-navigate-helper';
|
import { useNavigateHelper } from '../use-navigate-helper';
|
||||||
|
|
||||||
export function useOnTransformWorkspace() {
|
export function useOnTransformWorkspace() {
|
||||||
|
const t = useAFFiNEI18N();
|
||||||
const setSettingModal = useSetAtom(openSettingModalAtom);
|
const setSettingModal = useSetAtom(openSettingModalAtom);
|
||||||
const WorkspaceAdapters = useAtomValue(workspaceAdaptersAtom);
|
const WorkspaceAdapters = useAtomValue(workspaceAdaptersAtom);
|
||||||
const setMetadata = useSetAtom(rootWorkspacesMetadataAtom);
|
const setMetadata = useSetAtom(rootWorkspacesMetadataAtom);
|
||||||
const { openPage } = useNavigateHelper();
|
const { openPage } = useNavigateHelper();
|
||||||
const currentPageId = useAtomValue(currentPageIdAtom);
|
const currentPageId = useAtomValue(currentPageIdAtom);
|
||||||
|
const pushNotification = useSetAtom(pushNotificationAtom);
|
||||||
|
|
||||||
return useCallback(
|
return useCallback(
|
||||||
async <From extends WorkspaceFlavour, To extends WorkspaceFlavour>(
|
async <From extends WorkspaceFlavour, To extends WorkspaceFlavour>(
|
||||||
from: From,
|
from: From,
|
||||||
@@ -55,8 +60,20 @@ export function useOnTransformWorkspace() {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
openPage(newId, currentPageId ?? WorkspaceSubPath.ALL);
|
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,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,11 +6,12 @@ import {
|
|||||||
getInviteInfoQuery,
|
getInviteInfoQuery,
|
||||||
} from '@affine/graphql';
|
} from '@affine/graphql';
|
||||||
import { fetcher } from '@affine/workspace/affine/gql';
|
import { fetcher } from '@affine/workspace/affine/gql';
|
||||||
import { useAtom } from 'jotai';
|
import { useSetAtom } from 'jotai';
|
||||||
import { useCallback, useEffect } from 'react';
|
import { useCallback, useEffect } from 'react';
|
||||||
import { type LoaderFunction, redirect, useLoaderData } from 'react-router-dom';
|
import { type LoaderFunction, redirect, useLoaderData } from 'react-router-dom';
|
||||||
|
|
||||||
import { authAtom } from '../atoms';
|
import { authAtom } from '../atoms';
|
||||||
|
import { setOnceSignedInEventAtom } from '../atoms/event';
|
||||||
import { useCurrentLoginStatus } from '../hooks/affine/use-current-login-status';
|
import { useCurrentLoginStatus } from '../hooks/affine/use-current-login-status';
|
||||||
import { RouteLogic, useNavigateHelper } from '../hooks/use-navigate-helper';
|
import { RouteLogic, useNavigateHelper } from '../hooks/use-navigate-helper';
|
||||||
import { useAppHelper } from '../hooks/use-workspaces';
|
import { useAppHelper } from '../hooks/use-workspaces';
|
||||||
@@ -51,16 +52,14 @@ export const Component = () => {
|
|||||||
const { addCloudWorkspace } = useAppHelper();
|
const { addCloudWorkspace } = useAppHelper();
|
||||||
const { jumpToSubPath } = useNavigateHelper();
|
const { jumpToSubPath } = useNavigateHelper();
|
||||||
|
|
||||||
const [, setAuthAtom] = useAtom(authAtom);
|
const setOnceSignedInEvent = useSetAtom(setOnceSignedInEventAtom);
|
||||||
|
|
||||||
|
const setAuthAtom = useSetAtom(authAtom);
|
||||||
const { inviteInfo } = useLoaderData() as {
|
const { inviteInfo } = useLoaderData() as {
|
||||||
inviteId: string;
|
inviteId: string;
|
||||||
inviteInfo: GetInviteInfoQuery['getInviteInfo'];
|
inviteInfo: GetInviteInfoQuery['getInviteInfo'];
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadWorkspaceAfterSignIn = useCallback(() => {
|
|
||||||
addCloudWorkspace(inviteInfo.workspace.id);
|
|
||||||
}, [addCloudWorkspace, inviteInfo.workspace.id]);
|
|
||||||
|
|
||||||
const openWorkspace = useCallback(() => {
|
const openWorkspace = useCallback(() => {
|
||||||
addCloudWorkspace(inviteInfo.workspace.id);
|
addCloudWorkspace(inviteInfo.workspace.id);
|
||||||
jumpToSubPath(
|
jumpToSubPath(
|
||||||
@@ -73,10 +72,7 @@ export const Component = () => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (loginStatus === 'unauthenticated') {
|
if (loginStatus === 'unauthenticated') {
|
||||||
// We can not pass function to navigate state, so we need to save it in atom
|
// We can not pass function to navigate state, so we need to save it in atom
|
||||||
setAuthAtom(prev => ({
|
setOnceSignedInEvent(openWorkspace);
|
||||||
...prev,
|
|
||||||
onceSignedIn: loadWorkspaceAfterSignIn,
|
|
||||||
}));
|
|
||||||
jumpToSignIn(RouteLogic.REPLACE, {
|
jumpToSignIn(RouteLogic.REPLACE, {
|
||||||
state: {
|
state: {
|
||||||
callbackURL: `/workspace/${inviteInfo.workspace.id}/all`,
|
callbackURL: `/workspace/${inviteInfo.workspace.id}/all`,
|
||||||
@@ -86,9 +82,10 @@ export const Component = () => {
|
|||||||
}, [
|
}, [
|
||||||
inviteInfo.workspace.id,
|
inviteInfo.workspace.id,
|
||||||
jumpToSignIn,
|
jumpToSignIn,
|
||||||
loadWorkspaceAfterSignIn,
|
|
||||||
loginStatus,
|
loginStatus,
|
||||||
|
openWorkspace,
|
||||||
setAuthAtom,
|
setAuthAtom,
|
||||||
|
setOnceSignedInEvent,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (loginStatus === 'authenticated') {
|
if (loginStatus === 'authenticated') {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { useLocation, useNavigate } from 'react-router-dom';
|
|||||||
import { authAtom } from '../atoms';
|
import { authAtom } from '../atoms';
|
||||||
import { AuthPanel } from '../components/affine/auth';
|
import { AuthPanel } from '../components/affine/auth';
|
||||||
import { useCurrentLoginStatus } from '../hooks/affine/use-current-login-status';
|
import { useCurrentLoginStatus } from '../hooks/affine/use-current-login-status';
|
||||||
|
import { RouteLogic, useNavigateHelper } from '../hooks/use-navigate-helper';
|
||||||
|
|
||||||
interface LocationState {
|
interface LocationState {
|
||||||
state?: {
|
state?: {
|
||||||
@@ -14,36 +15,28 @@ interface LocationState {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
export const Component = () => {
|
export const Component = () => {
|
||||||
const [
|
const [{ state, email = '', emailType = 'changePassword' }, setAuthAtom] =
|
||||||
{ state, email = '', emailType = 'changePassword', onceSignedIn },
|
useAtom(authAtom);
|
||||||
setAuthAtom,
|
|
||||||
] = useAtom(authAtom);
|
|
||||||
const loginStatus = useCurrentLoginStatus();
|
const loginStatus = useCurrentLoginStatus();
|
||||||
const location = useLocation() as LocationState;
|
const location = useLocation() as LocationState;
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const { jumpToIndex } = useNavigateHelper();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const afterSignedIn = async () => {
|
|
||||||
if (loginStatus === 'authenticated') {
|
if (loginStatus === 'authenticated') {
|
||||||
if (onceSignedIn) {
|
|
||||||
await onceSignedIn();
|
|
||||||
setAuthAtom(prev => ({ ...prev, onceSignedIn: undefined }));
|
|
||||||
}
|
|
||||||
if (location.state?.callbackURL) {
|
if (location.state?.callbackURL) {
|
||||||
navigate(location.state.callbackURL, {
|
navigate(location.state.callbackURL, {
|
||||||
replace: true,
|
replace: true,
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
jumpToIndex(RouteLogic.REPLACE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
afterSignedIn().catch(err => {
|
|
||||||
console.error(err);
|
|
||||||
});
|
|
||||||
}, [
|
}, [
|
||||||
|
jumpToIndex,
|
||||||
location.state?.callbackURL,
|
location.state?.callbackURL,
|
||||||
loginStatus,
|
loginStatus,
|
||||||
navigate,
|
navigate,
|
||||||
onceSignedIn,
|
|
||||||
setAuthAtom,
|
setAuthAtom,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ export const AuthModal = (): ReactElement => {
|
|||||||
{ openModal, state, email = '', emailType = 'changePassword' },
|
{ openModal, state, email = '', emailType = 'changePassword' },
|
||||||
setAuthAtom,
|
setAuthAtom,
|
||||||
] = useAtom(authAtom);
|
] = useAtom(authAtom);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Auth
|
<Auth
|
||||||
open={openModal}
|
open={openModal}
|
||||||
|
|||||||
@@ -9,11 +9,14 @@ import { useSetAtom } from 'jotai';
|
|||||||
import { SessionProvider, useSession } from 'next-auth/react';
|
import { SessionProvider, useSession } from 'next-auth/react';
|
||||||
import { type PropsWithChildren, startTransition, useRef } from 'react';
|
import { type PropsWithChildren, startTransition, useRef } from 'react';
|
||||||
|
|
||||||
|
import { useOnceSignedInEvents } from '../atoms/event';
|
||||||
|
|
||||||
const SessionReporter = () => {
|
const SessionReporter = () => {
|
||||||
const session = useSession();
|
const session = useSession();
|
||||||
const prevSession = useRef<ReturnType<typeof useSession>>();
|
const prevSession = useRef<ReturnType<typeof useSession>>();
|
||||||
const pushNotification = useSetAtom(pushNotificationAtom);
|
const pushNotification = useSetAtom(pushNotificationAtom);
|
||||||
const refreshMetadata = useSetAtom(refreshRootMetadataAtom);
|
const refreshMetadata = useSetAtom(refreshRootMetadataAtom);
|
||||||
|
const onceSignedInEvents = useOnceSignedInEvents();
|
||||||
const t = useAFFiNEI18N();
|
const t = useAFFiNEI18N();
|
||||||
|
|
||||||
if (prevSession.current !== session && session.status !== 'loading') {
|
if (prevSession.current !== session && session.status !== 'loading') {
|
||||||
@@ -23,8 +26,10 @@ const SessionReporter = () => {
|
|||||||
session.status === 'authenticated'
|
session.status === 'authenticated'
|
||||||
) {
|
) {
|
||||||
startTransition(() => {
|
startTransition(() => {
|
||||||
|
onceSignedInEvents().then(() => {
|
||||||
refreshMetadata();
|
refreshMetadata();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
pushNotification({
|
pushNotification({
|
||||||
title: t['com.affine.auth.has.signed'](),
|
title: t['com.affine.auth.has.signed'](),
|
||||||
message: t['com.affine.auth.has.signed.message'](),
|
message: t['com.affine.auth.has.signed.message'](),
|
||||||
|
|||||||
@@ -569,5 +569,6 @@
|
|||||||
"Workspace Settings": "Workspace Settings",
|
"Workspace Settings": "Workspace Settings",
|
||||||
"Workspace Settings with name": "{{name}}'s Settings",
|
"Workspace Settings with name": "{{name}}'s Settings",
|
||||||
"Workspace Type": "Workspace Type",
|
"Workspace Type": "Workspace Type",
|
||||||
"You cannot delete the last workspace": "You cannot delete the last workspace"
|
"You cannot delete the last workspace": "You cannot delete the last workspace",
|
||||||
|
"Successfully enabled AFFiNE Cloud": "Successfully enabled AFFiNE Cloud"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user