feat(core): sidebar local workspace enable cloud directly (#6366)

- Add a new hook `useEnableClould`, remove `<EnableAffineClouldModal />`
- Sidebar local workspace list item support enable AFFiNE Cloud
This commit is contained in:
CatsJuice
2024-03-29 02:08:09 +00:00
parent 1a873ecf3c
commit 35715ab1d8
11 changed files with 273 additions and 211 deletions
@@ -1,10 +1,12 @@
import { UNTITLED_WORKSPACE_NAME } from '@affine/env/constant';
import type { WorkspaceFlavour } from '@affine/env/workspace';
import { WorkspaceFlavour } from '@affine/env/workspace';
import { CollaborationIcon, SettingsIcon } from '@blocksuite/icons';
import type { WorkspaceMetadata } from '@toeverything/infra';
import { useCallback } from 'react';
import clsx from 'clsx';
import { type MouseEvent, useCallback } from 'react';
import { Avatar, type AvatarProps } from '../../../ui/avatar';
import { Button } from '../../../ui/button';
import { Skeleton } from '../../../ui/skeleton';
import * as styles from './styles.css';
@@ -18,7 +20,10 @@ export interface WorkspaceCardProps {
meta: WorkspaceMetadata;
onClick: (metadata: WorkspaceMetadata) => void;
onSettingClick: (metadata: WorkspaceMetadata) => void;
onEnableCloudClick?: (meta: WorkspaceMetadata) => void;
isOwner?: boolean;
openingId?: string | null;
enableCloudText?: string;
avatar?: string;
name?: string;
}
@@ -45,13 +50,25 @@ const avatarImageProps = {
export const WorkspaceCard = ({
onClick,
onSettingClick,
onEnableCloudClick,
openingId,
currentWorkspaceId,
meta,
isOwner = true,
enableCloudText = 'Enable Cloud',
name,
avatar,
}: WorkspaceCardProps) => {
const isLocal = meta.flavour === WorkspaceFlavour.LOCAL;
const displayName = name ?? UNTITLED_WORKSPACE_NAME;
const onEnableCloud = useCallback(
(e: MouseEvent) => {
e.stopPropagation();
onEnableCloudClick?.(meta);
},
[meta, onEnableCloudClick]
);
return (
<div
className={styles.card}
@@ -73,6 +90,17 @@ export const WorkspaceCard = ({
<div className={styles.workspaceTitle}>{displayName}</div>
<div className={styles.actionButtons}>
{isLocal ? (
<Button
loading={!!openingId && openingId === meta.id}
disabled={!!openingId}
type="default"
className={clsx(styles.enableCloudButton, styles.showOnCardHover)}
onClick={onEnableCloud}
>
{enableCloudText}
</Button>
) : null}
{isOwner ? null : <CollaborationIcon />}
<div
className={styles.settingButton}
@@ -84,3 +84,16 @@ export const settingButton = style({
// },
},
});
export const enableCloudButton = style({
background: 'transparent',
});
export const showOnCardHover = style({
display: 'none',
selectors: {
[`.${card}:hover &`]: {
display: 'block',
},
},
});
@@ -19,8 +19,10 @@ export interface WorkspaceListProps {
disabled?: boolean;
currentWorkspaceId?: string | null;
items: WorkspaceMetadata[];
openingId?: string | null;
onClick: (workspace: WorkspaceMetadata) => void;
onSettingClick: (workspace: WorkspaceMetadata) => void;
onEnableCloudClick?: (meta: WorkspaceMetadata) => void;
onDragEnd: (event: DragEndEvent) => void;
useIsWorkspaceOwner: (workspaceMetadata: WorkspaceMetadata) => boolean;
useWorkspaceAvatar: (
@@ -38,12 +40,14 @@ interface SortableWorkspaceItemProps extends Omit<WorkspaceListProps, 'items'> {
const SortableWorkspaceItem = ({
disabled,
item,
openingId,
useIsWorkspaceOwner,
useWorkspaceAvatar,
useWorkspaceName,
currentWorkspaceId,
onClick,
onSettingClick,
onEnableCloudClick,
}: SortableWorkspaceItemProps) => {
const { setNodeRef, attributes, listeners, transform, transition } =
useSortable({
@@ -77,6 +81,8 @@ const SortableWorkspaceItem = ({
meta={item}
onClick={onClick}
onSettingClick={onSettingClick}
onEnableCloudClick={onEnableCloudClick}
openingId={openingId}
isOwner={isOwner}
name={name}
avatar={avatar}
@@ -56,9 +56,16 @@ export const ConfirmModal = ({
);
};
interface OpenConfirmModalOptions {
autoClose?: boolean;
onSuccess?: () => void;
}
interface ConfirmModalContextProps {
modalProps: ConfirmModalProps;
openConfirmModal: (props?: ConfirmModalProps) => void;
openConfirmModal: (
props?: ConfirmModalProps,
options?: OpenConfirmModalOptions
) => void;
closeConfirmModal: () => void;
}
const ConfirmModalContext = createContext<ConfirmModalContextProps>({
@@ -86,7 +93,8 @@ export const ConfirmModalProvider = ({ children }: PropsWithChildren) => {
}, []);
const openConfirmModal = useCallback(
(props?: ConfirmModalProps) => {
(props?: ConfirmModalProps, options?: OpenConfirmModalOptions) => {
const { autoClose = true, onSuccess } = options ?? {};
if (!props) {
setModalProps({ open: true });
return;
@@ -97,17 +105,22 @@ export const ConfirmModalProvider = ({ children }: PropsWithChildren) => {
const onConfirm = () => {
setLoading(true);
_onConfirm?.()
?.catch(console.error)
?.finally(() => closeConfirmModal());
?.then(() => onSuccess?.())
.catch(console.error)
.finally(() => autoClose && closeConfirmModal());
};
setModalProps({ ...otherProps, onConfirm, open: true });
},
[closeConfirmModal, setLoading]
);
const onOpenChange = useCallback((open: boolean) => {
setModalProps(props => ({ ...props, open }));
}, []);
const onOpenChange = useCallback(
(open: boolean) => {
modalProps.onOpenChange?.(open);
setModalProps(props => ({ ...props, open }));
},
[modalProps]
);
return (
<ConfirmModalContext.Provider
@@ -115,7 +128,7 @@ export const ConfirmModalProvider = ({ children }: PropsWithChildren) => {
>
{children}
{/* TODO: multi-instance support(unnecessary for now) */}
<ConfirmModal onOpenChange={onOpenChange} {...modalProps} />
<ConfirmModal {...modalProps} onOpenChange={onOpenChange} />
</ConfirmModalContext.Provider>
);
};
@@ -1,54 +0,0 @@
import type { ConfirmModalProps } from '@affine/component/ui/modal';
import { ConfirmModal } from '@affine/component/ui/modal';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
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';
export const EnableAffineCloudModal = ({
onConfirm: propsOnConfirm,
...props
}: Omit<ConfirmModalProps, 'onConfirm'> & { onConfirm: () => void }) => {
const t = useAFFiNEI18N();
const loginStatus = useCurrentLoginStatus();
const setAuthAtom = useSetAtom(authAtom);
const setOnceSignedInEvent = useSetAtom(setOnceSignedInEventAtom);
const confirm = useCallback(() => {
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 (
<ConfirmModal
title={t['Enable AFFiNE Cloud']()}
description={t['Enable AFFiNE Cloud Description']()}
cancelText={t['com.affine.enableAffineCloudModal.button.cancel']()}
onConfirm={onConfirm}
confirmButtonOptions={{
type: 'primary',
['data-testid' as string]: 'confirm-enable-affine-cloud-button',
children:
loginStatus === 'authenticated'
? t['Enable']()
: t['Sign in and Enable'](),
}}
{...props}
/>
);
};
@@ -3,64 +3,43 @@ import {
openDisableCloudAlertModalAtom,
openHistoryTipsModalAtom,
} from '@affine/core/atoms';
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
import { useNavigateHelper } from '@affine/core/hooks/use-navigate-helper';
import { WorkspaceSubPath } from '@affine/core/shared';
import { useEnableCloud } from '@affine/core/hooks/affine/use-enable-cloud';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { useService, Workspace, WorkspaceManager } from '@toeverything/infra';
import { useService, Workspace } from '@toeverything/infra';
import { useAtom, useSetAtom } from 'jotai';
import { useCallback, useState } from 'react';
import { useCallback } from 'react';
import { EnableAffineCloudModal } from '../enable-affine-cloud-modal';
import TopSvg from './top-svg';
export const HistoryTipsModal = () => {
const t = useAFFiNEI18N();
const { openPage } = useNavigateHelper();
const workspaceManager = useService(WorkspaceManager);
const currentWorkspace = useService(Workspace);
const [open, setOpen] = useAtom(openHistoryTipsModalAtom);
const setTempDisableCloudOpen = useSetAtom(openDisableCloudAlertModalAtom);
const [openEnableCloudModal, setOpenEnableCloudModal] = useState(false);
const confirmEnableCloud = useEnableCloud();
const handleConfirm = useCallback(() => {
setOpen(false);
if (runtimeConfig.enableCloud) {
return setOpenEnableCloudModal(true);
}
return setTempDisableCloudOpen(true);
}, [setOpen, setTempDisableCloudOpen]);
const handEnableCloud = useAsyncCallback(async () => {
if (!currentWorkspace) {
confirmEnableCloud(currentWorkspace);
return;
}
const { id: newId } =
await workspaceManager.transformLocalToCloud(currentWorkspace);
openPage(newId, WorkspaceSubPath.ALL);
setOpenEnableCloudModal(false);
}, [openPage, currentWorkspace, workspaceManager]);
return setTempDisableCloudOpen(true);
}, [confirmEnableCloud, currentWorkspace, setOpen, setTempDisableCloudOpen]);
return (
<>
<OverlayModal
open={open}
topImage={<TopSvg />}
title={t['com.affine.history-vision.tips-modal.title']()}
onOpenChange={setOpen}
description={t['com.affine.history-vision.tips-modal.description']()}
cancelText={t['com.affine.history-vision.tips-modal.cancel']()}
confirmButtonOptions={{
type: 'primary',
}}
onConfirm={handleConfirm}
confirmText={t['com.affine.history-vision.tips-modal.confirm']()}
/>
<EnableAffineCloudModal
open={openEnableCloudModal}
onOpenChange={setOpenEnableCloudModal}
onConfirm={handEnableCloud}
/>
</>
<OverlayModal
open={open}
topImage={<TopSvg />}
title={t['com.affine.history-vision.tips-modal.title']()}
onOpenChange={setOpen}
description={t['com.affine.history-vision.tips-modal.description']()}
cancelText={t['com.affine.history-vision.tips-modal.cancel']()}
confirmButtonOptions={{
type: 'primary',
}}
onConfirm={handleConfirm}
confirmText={t['com.affine.history-vision.tips-modal.confirm']()}
/>
);
};
@@ -1,19 +1,15 @@
import { SettingRow } from '@affine/component/setting-components';
import { Button } from '@affine/component/ui/button';
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
import { useEnableCloud } from '@affine/core/hooks/affine/use-enable-cloud';
import { useWorkspaceInfo } from '@affine/core/hooks/use-workspace-info';
import { UNTITLED_WORKSPACE_NAME } from '@affine/env/constant';
import { WorkspaceFlavour } from '@affine/env/workspace';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import type { Workspace } from '@toeverything/infra';
import { useService, WorkspaceManager } from '@toeverything/infra';
import { useSetAtom } from 'jotai';
import { useState } from 'react';
import { useCallback, useState } from 'react';
import { openSettingModalAtom } from '../../../../../atoms';
import { useNavigateHelper } from '../../../../../hooks/use-navigate-helper';
import { WorkspaceSubPath } from '../../../../../shared';
import { EnableAffineCloudModal } from '../../../enable-affine-cloud-modal';
import { TmpDisableAffineCloudModal } from '../../../tmp-disable-affine-cloud-modal';
import type { WorkspaceSettingDetailProps } from './types';
@@ -26,28 +22,21 @@ export const EnableCloudPanel = ({
workspace,
}: PublishPanelProps) => {
const t = useAFFiNEI18N();
const confirmEnableCloud = useEnableCloud();
const { openPage } = useNavigateHelper();
const workspaceManager = useService(WorkspaceManager);
const workspaceInfo = useWorkspaceInfo(workspaceMetadata);
const setSettingModal = useSetAtom(openSettingModalAtom);
const [open, setOpen] = useState(false);
const handleEnableCloud = useAsyncCallback(async () => {
if (!workspace) {
return;
}
const { id: newId } =
await workspaceManager.transformLocalToCloud(workspace);
openPage(newId, WorkspaceSubPath.ALL);
setOpen(false);
setSettingModal(settings => ({
...settings,
open: false,
}));
}, [openPage, setSettingModal, workspace, workspaceManager]);
const confirmEnableCloudAndClose = useCallback(() => {
if (!workspace) return;
confirmEnableCloud(workspace, {
onSuccess: () => {
setSettingModal(settings => ({ ...settings, open: false }));
},
});
}, [confirmEnableCloud, setSettingModal, workspace]);
if (workspaceMetadata.flavour !== WorkspaceFlavour.LOCAL) {
return null;
@@ -69,21 +58,13 @@ export const EnableCloudPanel = ({
<Button
data-testid="publish-enable-affine-cloud-button"
type="primary"
onClick={() => {
setOpen(true);
}}
onClick={confirmEnableCloudAndClose}
style={{ marginTop: '12px' }}
>
{t['Enable AFFiNE Cloud']()}
</Button>
</SettingRow>
{runtimeConfig.enableCloud ? (
<EnableAffineCloudModal
open={open}
onOpenChange={setOpen}
onConfirm={handleEnableCloud}
/>
) : (
{runtimeConfig.enableCloud ? null : (
<TmpDisableAffineCloudModal open={open} onOpenChange={setOpen} />
)}
</>
@@ -1,12 +1,7 @@
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
import { WorkspaceFlavour } from '@affine/env/workspace';
import { useEnableCloud } from '@affine/core/hooks/affine/use-enable-cloud';
import type { Doc } from '@blocksuite/store';
import type { Workspace } from '@toeverything/infra';
import { useService, WorkspaceManager } from '@toeverything/infra';
import { useState } from 'react';
import { useNavigateHelper } from '../../../hooks/use-navigate-helper';
import { EnableAffineCloudModal } from '../enable-affine-cloud-modal';
import { ShareMenu } from './share-menu';
type SharePageModalProps = {
@@ -20,37 +15,18 @@ export const SharePageButton = ({
page,
isJournal,
}: SharePageModalProps) => {
const [open, setOpen] = useState(false);
const { openPage } = useNavigateHelper();
const workspaceManager = useService(WorkspaceManager);
const handleConfirm = useAsyncCallback(async () => {
if (workspace.flavour !== WorkspaceFlavour.LOCAL) {
return;
}
const { id: newId } =
await workspaceManager.transformLocalToCloud(workspace);
openPage(newId, page.id);
setOpen(false);
}, [openPage, page.id, workspace, workspaceManager]);
const confirmEnableCloud = useEnableCloud();
return (
<>
<ShareMenu
isJournal={isJournal}
workspaceMetadata={workspace.meta}
currentPage={page}
onEnableAffineCloud={() => setOpen(true)}
/>
{workspace.flavour === WorkspaceFlavour.LOCAL ? (
<EnableAffineCloudModal
open={open}
onOpenChange={setOpen}
onConfirm={handleConfirm}
/>
) : null}
</>
<ShareMenu
isJournal={isJournal}
workspaceMetadata={workspace.meta}
currentPage={page}
onEnableAffineCloud={() =>
confirmEnableCloud(workspace, {
openPageId: page.id,
})
}
/>
);
};
@@ -2,6 +2,7 @@ import { ScrollableContainer } from '@affine/component';
import { Divider } from '@affine/component/ui/divider';
import { WorkspaceList } from '@affine/component/workspace-list';
import { useSession } from '@affine/core/hooks/affine/use-current-user';
import { useEnableCloud } from '@affine/core/hooks/affine/use-enable-cloud';
import {
useWorkspaceAvatar,
useWorkspaceName,
@@ -13,7 +14,7 @@ import type { DragEndEvent } from '@dnd-kit/core';
import type { WorkspaceMetadata } from '@toeverything/infra';
import { useLiveData, useService, WorkspaceManager } from '@toeverything/infra';
import { useSetAtom } from 'jotai';
import { useCallback, useMemo } from 'react';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import {
openCreateWorkspaceModalAtom,
@@ -28,8 +29,10 @@ interface WorkspaceModalProps {
disabled?: boolean;
workspaces: WorkspaceMetadata[];
currentWorkspaceId?: string | null;
openingId?: string | null;
onClickWorkspace: (workspaceMetadata: WorkspaceMetadata) => void;
onClickWorkspaceSetting: (workspaceMetadata: WorkspaceMetadata) => void;
onClickEnableCloud?: (meta: WorkspaceMetadata) => void;
onNewWorkspace: () => void;
onAddWorkspace: () => void;
onDragEnd: (event: DragEndEvent) => void;
@@ -77,6 +80,8 @@ const LocalWorkspaces = ({
workspaces,
onClickWorkspace,
onClickWorkspaceSetting,
onClickEnableCloud,
openingId,
currentWorkspaceId,
onDragEnd,
}: WorkspaceModalProps) => {
@@ -95,11 +100,13 @@ const LocalWorkspaces = ({
{t['com.affine.workspaceList.workspaceListType.local']()}
</div>
<WorkspaceList
openingId={openingId}
disabled={disabled}
items={workspaces}
currentWorkspaceId={currentWorkspaceId}
onClick={onClickWorkspace}
onSettingClick={onClickWorkspaceSetting}
onEnableCloudClick={onClickEnableCloud}
onDragEnd={onDragEnd}
useIsWorkspaceOwner={useIsWorkspaceOwner}
useWorkspaceName={useWorkspaceName}
@@ -114,11 +121,13 @@ export const AFFiNEWorkspaceList = ({
}: {
onEventEnd?: () => void;
}) => {
const workspaces = useLiveData(
useService(WorkspaceManager).list.workspaceList$
);
const openWsRef = useRef<ReturnType<typeof workspaceManager.open>>();
const workspaceManager = useService(WorkspaceManager);
const workspaces = useLiveData(workspaceManager.list.workspaceList$);
const setOpenCreateWorkspaceModal = useSetAtom(openCreateWorkspaceModalAtom);
const [openingId, setOpeningId] = useState<string | null>(null);
const confirmEnableCloud = useEnableCloud();
const { jumpToSubPath } = useNavigateHelper();
@@ -160,6 +169,28 @@ export const AFFiNEWorkspaceList = ({
[onEventEnd, setOpenSettingModalAtom]
);
const onClickEnableCloud = useCallback(
(meta: WorkspaceMetadata) => {
openWsRef.current?.release();
openWsRef.current = workspaceManager.open(meta);
confirmEnableCloud(openWsRef.current.workspace, {
onFinished: () => {
openWsRef.current?.release();
openWsRef.current = undefined;
setOpeningId(null);
},
});
setOpeningId(meta.id);
},
[confirmEnableCloud, workspaceManager]
);
useEffect(() => {
return () => {
openWsRef.current?.release();
};
}, []);
const onMoveWorkspace = useCallback((_activeId: string, _overId: string) => {
// TODO: order
// const oldIndex = workspaces.findIndex(w => w.id === activeId);
@@ -219,9 +250,11 @@ export const AFFiNEWorkspaceList = ({
</div>
) : null}
<LocalWorkspaces
openingId={openingId}
workspaces={localWorkspaces}
onClickWorkspace={onClickWorkspace}
onClickWorkspaceSetting={onClickWorkspaceSetting}
onClickEnableCloud={onClickEnableCloud}
onNewWorkspace={onNewWorkspace}
onAddWorkspace={onAddWorkspace}
currentWorkspaceId={currentWorkspace?.id}
@@ -1,18 +1,14 @@
import { BrowserWarning, LocalDemoTips } from '@affine/component/affine-banner';
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
import { WorkspaceFlavour } from '@affine/env/workspace';
import { Trans } from '@affine/i18n';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import type { Workspace } from '@toeverything/infra';
import { useService, WorkspaceManager } from '@toeverything/infra';
import { useSetAtom } from 'jotai';
import { useCallback, useState } from 'react';
import { authAtom } from '../atoms';
import { useCurrentLoginStatus } from '../hooks/affine/use-current-login-status';
import { useNavigateHelper } from '../hooks/use-navigate-helper';
import { WorkspaceSubPath } from '../shared';
import { EnableAffineCloudModal } from './affine/enable-affine-cloud-modal';
import { useEnableCloud } from '../hooks/affine/use-enable-cloud';
const minimumChromeVersion = 106;
@@ -68,47 +64,29 @@ export const TopTip = ({
const [showWarning, setShowWarning] = useState(shouldShowWarning);
const [showLocalDemoTips, setShowLocalDemoTips] = useState(true);
const [open, setOpen] = useState(false);
const confirmEnableCloud = useEnableCloud();
const setAuthModal = useSetAtom(authAtom);
const onLogin = useCallback(() => {
setAuthModal({ openModal: true, state: 'signIn' });
}, [setAuthModal]);
const { openPage } = useNavigateHelper();
const workspaceManager = useService(WorkspaceManager);
const handleConfirm = useAsyncCallback(async () => {
if (workspace.flavour !== WorkspaceFlavour.LOCAL) {
return;
}
// TODO: we need to transform local to cloud
const { id: newId } =
await workspaceManager.transformLocalToCloud(workspace);
openPage(newId, pageId || WorkspaceSubPath.ALL);
setOpen(false);
}, [openPage, pageId, workspace, workspaceManager]);
if (
showLocalDemoTips &&
!environment.isDesktop &&
workspace.flavour === WorkspaceFlavour.LOCAL
) {
return (
<>
<LocalDemoTips
isLoggedIn={isLoggedIn}
onLogin={onLogin}
onEnableCloud={() => setOpen(true)}
onClose={() => {
setShowLocalDemoTips(false);
}}
/>
<EnableAffineCloudModal
open={open}
onOpenChange={setOpen}
onConfirm={handleConfirm}
/>
</>
<LocalDemoTips
isLoggedIn={isLoggedIn}
onLogin={onLogin}
onEnableCloud={() =>
confirmEnableCloud(workspace, { openPageId: pageId })
}
onClose={() => {
setShowLocalDemoTips(false);
}}
/>
);
}
@@ -0,0 +1,109 @@
import { useConfirmModal } from '@affine/component';
import { authAtom } from '@affine/core/atoms';
import { setOnceSignedInEventAtom } from '@affine/core/atoms/event';
import { WorkspaceSubPath } from '@affine/core/shared';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import type { Workspace } from '@toeverything/infra';
import { useService, WorkspaceManager } from '@toeverything/infra';
import { useSetAtom } from 'jotai';
import { useCallback } from 'react';
import { useNavigateHelper } from '../use-navigate-helper';
import { useCurrentLoginStatus } from './use-current-login-status';
interface ConfirmEnableCloudOptions {
/**
* Fired when the workspace is successfully enabled
*/
onSuccess?: () => void;
/**
* Fired when workspace is successfully enabled or user cancels the operation
*/
onFinished?: () => void;
openPageId?: string;
}
type ConfirmEnableArgs = [Workspace, ConfirmEnableCloudOptions | undefined];
export const useEnableCloud = () => {
const t = useAFFiNEI18N();
const loginStatus = useCurrentLoginStatus();
const setAuthAtom = useSetAtom(authAtom);
const setOnceSignedInEvent = useSetAtom(setOnceSignedInEventAtom);
const { openConfirmModal, closeConfirmModal } = useConfirmModal();
const workspaceManager = useService(WorkspaceManager);
const { openPage } = useNavigateHelper();
const enableCloud = useCallback(
async (ws: Workspace | null, options?: ConfirmEnableCloudOptions) => {
if (!ws) return;
const { id: newId } = await workspaceManager.transformLocalToCloud(ws);
openPage(newId, options?.openPageId || WorkspaceSubPath.ALL);
options?.onSuccess?.();
},
[openPage, workspaceManager]
);
const openSignIn = useCallback(
(...args: ConfirmEnableArgs) => {
setAuthAtom(prev => ({ ...prev, openModal: true }));
setOnceSignedInEvent(() => {
enableCloud(...args).catch(console.error);
});
},
[enableCloud, setAuthAtom, setOnceSignedInEvent]
);
const signInOrEnableCloud = useCallback(
async (...args: ConfirmEnableArgs) => {
// not logged in, open login modal
if (loginStatus === 'unauthenticated') {
openSignIn(...args);
}
if (loginStatus === 'authenticated') {
await enableCloud(...args);
}
},
[enableCloud, loginStatus, openSignIn]
);
const confirmEnableCloud = useCallback(
(ws: Workspace, options?: ConfirmEnableCloudOptions) => {
const { onSuccess, onFinished } = options ?? {};
if (!runtimeConfig.enableCloud) return;
const closeOnSuccess = () => {
closeConfirmModal();
onSuccess?.();
};
openConfirmModal(
{
title: t['Enable AFFiNE Cloud'](),
description: t['Enable AFFiNE Cloud Description'](),
cancelText: t['com.affine.enableAffineCloudModal.button.cancel'](),
confirmButtonOptions: {
type: 'primary',
['data-testid' as string]: 'confirm-enable-affine-cloud-button',
children:
loginStatus === 'authenticated'
? t['Enable']()
: t['Sign in and Enable'](),
},
onConfirm: async () =>
await signInOrEnableCloud(ws, {
...options,
onSuccess: closeOnSuccess,
}),
onOpenChange: open => {
if (!open) onFinished?.();
},
},
{ autoClose: false }
);
},
[closeConfirmModal, loginStatus, openConfirmModal, signInOrEnableCloud, t]
);
return confirmEnableCloud;
};