From 0db7868a6a9dab4c4d936b5d9008a20adcd3285a Mon Sep 17 00:00:00 2001 From: Qi <474021214@qq.com> Date: Thu, 9 Mar 2023 02:40:25 +0800 Subject: [PATCH] feat: open last workspace when back or refresh affine (#1413) Co-authored-by: himself65 --- .../affine/use-last-leave-workspace-id.ts | 7 +++++ .../hooks/current/use-current-workspace.ts | 12 ++++++-- apps/web/src/pages/_app.tsx | 1 - apps/web/src/pages/index.tsx | 29 +++++++++++------- tests/open-affine.spec.ts | 30 +++++++++++++++++++ 5 files changed, 65 insertions(+), 14 deletions(-) create mode 100644 apps/web/src/hooks/affine/use-last-leave-workspace-id.ts create mode 100644 tests/open-affine.spec.ts diff --git a/apps/web/src/hooks/affine/use-last-leave-workspace-id.ts b/apps/web/src/hooks/affine/use-last-leave-workspace-id.ts new file mode 100644 index 0000000000..46dcc86ab5 --- /dev/null +++ b/apps/web/src/hooks/affine/use-last-leave-workspace-id.ts @@ -0,0 +1,7 @@ +import { useAtomValue } from 'jotai'; + +import { lastWorkspaceIdAtom } from '../current/use-current-workspace'; + +export function useLastWorkspaceId() { + return useAtomValue(lastWorkspaceIdAtom); +} diff --git a/apps/web/src/hooks/current/use-current-workspace.ts b/apps/web/src/hooks/current/use-current-workspace.ts index 293573d829..d9f3092df0 100644 --- a/apps/web/src/hooks/current/use-current-workspace.ts +++ b/apps/web/src/hooks/current/use-current-workspace.ts @@ -1,4 +1,5 @@ -import { atom, useAtom, useAtomValue } from 'jotai'; +import { atom, useAtom, useAtomValue, useSetAtom } from 'jotai'; +import { atomWithStorage } from 'jotai/utils'; import { useCallback } from 'react'; import { @@ -16,6 +17,11 @@ export const currentWorkspaceAtom = atom>( } ); +export const lastWorkspaceIdAtom = atomWithStorage( + 'last_workspace_id', + null +); + export function useCurrentWorkspace(): [ RemWorkspace | null, (id: string | null) => void @@ -23,14 +29,16 @@ export function useCurrentWorkspace(): [ const currentWorkspace = useAtomValue(currentWorkspaceAtom); const [, setId] = useAtom(currentWorkspaceIdAtom); const [, setPageId] = useAtom(currentPageIdAtom); + const setLast = useSetAtom(lastWorkspaceIdAtom); return [ currentWorkspace, useCallback( (id: string | null) => { setPageId(null); + setLast(id); setId(id); }, - [setId, setPageId] + [setId, setLast, setPageId] ), ]; } diff --git a/apps/web/src/pages/_app.tsx b/apps/web/src/pages/_app.tsx index 9f405e7c4b..79615c08d6 100644 --- a/apps/web/src/pages/_app.tsx +++ b/apps/web/src/pages/_app.tsx @@ -45,7 +45,6 @@ const App = function App({ }) { const getLayout = Component.getLayout || EmptyLayout; const i18n = useMemo(() => createI18n(), []); - if (process.env.NODE_ENV === 'development') { // I know what I'm doing // eslint-disable-next-line react-hooks/rules-of-hooks diff --git a/apps/web/src/pages/index.tsx b/apps/web/src/pages/index.tsx index ab61156487..6385f3d416 100644 --- a/apps/web/src/pages/index.tsx +++ b/apps/web/src/pages/index.tsx @@ -3,25 +3,32 @@ import { useRouter } from 'next/router'; import React, { Suspense, useEffect } from 'react'; import { PageLoading } from '../components/pure/loading'; +import { useLastWorkspaceId } from '../hooks/affine/use-last-leave-workspace-id'; import { useCreateFirstWorkspace } from '../hooks/use-create-first-workspace'; import { useWorkspaces } from '../hooks/use-workspaces'; const IndexPageInner = () => { const router = useRouter(); const workspaces = useWorkspaces(); + const lastWorkspaceId = useLastWorkspaceId(); + useEffect(() => { if (!router.isReady) { return; } - const firstWorkspace = workspaces.at(0); - if (firstWorkspace) { + const targetWorkspace = + (lastWorkspaceId && + workspaces.find(({ id }) => id === lastWorkspaceId)) || + workspaces.at(0); + + if (targetWorkspace) { const pageId = - firstWorkspace.blockSuiteWorkspace.meta.pageMetas.at(0)?.id; + targetWorkspace.blockSuiteWorkspace.meta.pageMetas.at(0)?.id; if (pageId) { router.replace({ pathname: '/workspace/[workspaceId]/[pageId]', query: { - workspaceId: firstWorkspace.id, + workspaceId: targetWorkspace.id, pageId, }, }); @@ -32,29 +39,29 @@ const IndexPageInner = () => { router.replace({ pathname: '/workspace/[workspaceId]/all', query: { - workspaceId: firstWorkspace.id, + workspaceId: targetWorkspace.id, }, }); }, 1000); - const dispose = firstWorkspace.blockSuiteWorkspace.slots.pageAdded.once( - pageId => { + const dispose = + targetWorkspace.blockSuiteWorkspace.slots.pageAdded.once(pageId => { clearTimeout(clearId); router.replace({ pathname: '/workspace/[workspaceId]/[pageId]', query: { - workspaceId: firstWorkspace.id, + workspaceId: targetWorkspace.id, pageId, }, }); - } - ); + }); return () => { clearTimeout(clearId); dispose.dispose(); }; } } - }, [router, workspaces]); + }, [lastWorkspaceId, router, workspaces]); + return ; }; diff --git a/tests/open-affine.spec.ts b/tests/open-affine.spec.ts new file mode 100644 index 0000000000..0e690a61b0 --- /dev/null +++ b/tests/open-affine.spec.ts @@ -0,0 +1,30 @@ +import { expect } from '@playwright/test'; + +import { loadPage } from './libs/load-page'; +import { test } from './libs/playwright'; +import { createWorkspace } from './libs/workspace-logic'; + +loadPage(); + +test.describe('Open AFFiNE', () => { + test('Open last workspace when back to affine', async ({ page }) => { + await createWorkspace({ name: 'New Workspace 2' }, page); + // FIXME: can not get when the new workspace is surely created, hack a timeout to wait + // waiting for page loading end + await page.waitForTimeout(3000); + // show workspace list + await page.getByTestId('workspace-name').click(); + + //check workspace list length + const workspaceCards = await page.$$('data-testid=workspace-card'); + expect(workspaceCards.length).toBe(2); + await workspaceCards[1].click(); + await page.goto('http://localhost:8080'); + + const workspaceNameDom = await page.getByTestId('workspace-name'); + const currentWorkspaceName = await workspaceNameDom.evaluate( + node => node.textContent + ); + expect(currentWorkspaceName).toEqual('New Workspace 2'); + }); +});