chore: move client folders (#948)

This commit is contained in:
DarkSky
2023-02-10 20:41:01 +08:00
committed by GitHub
parent cb118149f3
commit 8a7393a961
235 changed files with 114 additions and 215 deletions
@@ -0,0 +1,22 @@
import { useCallback } from 'react';
import { useAppState, PageMeta } from '@/providers/app-state-provider';
export type ChangePageMeta = (
pageId: string,
pageMeta: Partial<PageMeta>
) => void;
export const useChangePageMeta = () => {
const { currentWorkspace } = useAppState();
return useCallback<ChangePageMeta>(
(pageId, pageMeta) => {
currentWorkspace?.blocksuiteWorkspace?.setPageMeta(pageId, {
...pageMeta,
});
},
[currentWorkspace]
);
};
export default ChangePageMeta;
@@ -0,0 +1,39 @@
import { useCallback, useEffect, useState } from 'react';
import { useAppState, PageMeta } from '@/providers/app-state-provider';
export const useCurrentPageMeta = (): PageMeta | null => {
const { currentPage, currentWorkspace } = useAppState();
const pageMetaHandler = useCallback((): PageMeta | null => {
if (!currentPage || !currentWorkspace) {
return null;
}
return (
(currentWorkspace.blocksuiteWorkspace?.meta.pageMetas.find(
p => p.id === currentPage.id
) as PageMeta) ?? null
);
}, [currentPage, currentWorkspace]);
const [currentPageMeta, setCurrentPageMeta] = useState<PageMeta | null>(
pageMetaHandler
);
useEffect(() => {
setCurrentPageMeta(pageMetaHandler);
const dispose = currentWorkspace?.blocksuiteWorkspace?.meta.pagesUpdated.on(
() => {
setCurrentPageMeta(pageMetaHandler);
}
).dispose;
return () => {
dispose?.();
};
}, [currentPage, currentWorkspace, pageMetaHandler]);
return currentPageMeta;
};
export default useCurrentPageMeta;
@@ -0,0 +1,53 @@
import { useState, useEffect } from 'react';
import { useAppState } from '@/providers/app-state-provider';
import { useRouter } from 'next/router';
// It is a fully effective hook
// Cause it not just ensure workspace loaded, but also have router change.
export const useEnsureWorkspace = () => {
const [workspaceLoaded, setWorkspaceLoaded] = useState(false);
const { workspaceList, loadWorkspace, user } = useAppState();
const router = useRouter();
const [activeWorkspaceId, setActiveWorkspaceId] = useState(
router.query.workspaceId as string
);
// const defaultOutLineWorkspaceId = '99ce7eb7';
// console.log(defaultOutLineWorkspaceId);
useEffect(() => {
// If router.query.workspaceId is not in workspace list, jump to 404 page
// If workspaceList is empty, we need to create a default workspace but not jump to 404
if (
workspaceList.length &&
// FIXME: router is not ready when this hook is called
location.pathname.startsWith(`/workspace/${router.query.workspaceId}`) &&
workspaceList.findIndex(
meta => meta.id.toString() === router.query.workspaceId
) === -1
) {
router.push('/404');
return;
}
// If user is not login and input a custom workspaceId, jump to 404 page
// if (
// !user &&
// router.query.workspaceId &&
// router.query.workspaceId !== defaultOutLineWorkspaceId
// ) {
// router.push('/404');
// return;
// }
const workspaceId =
(router.query.workspaceId as string) || workspaceList[0]?.id;
loadWorkspace.current(workspaceId).finally(() => {
setWorkspaceLoaded(true);
setActiveWorkspaceId(activeWorkspaceId);
});
}, [loadWorkspace, router, user, workspaceList, activeWorkspaceId]);
return {
workspaceLoaded,
activeWorkspaceId,
};
};
export default useEnsureWorkspace;
+37
View File
@@ -0,0 +1,37 @@
import { Page } from '@blocksuite/store';
import { useAppState } from '@/providers/app-state-provider';
import { useEffect, useRef } from 'react';
export type EventCallBack<T> = (callback: (props: T) => void) => void;
export type UseHistoryUpdated = (page?: Page) => EventCallBack<Page>;
export const useHistoryUpdate: UseHistoryUpdated = () => {
const { currentPage } = useAppState();
const callbackQueue = useRef<((page: Page) => void)[]>([]);
useEffect(() => {
if (!currentPage) {
return;
}
setTimeout(() => {
currentPage.signals.historyUpdated.on(() => {
callbackQueue.current.forEach(callback => {
callback(currentPage);
});
});
}, 300);
return () => {
callbackQueue.current = [];
currentPage.signals.historyUpdated.dispose();
};
}, [currentPage]);
return callback => {
callbackQueue.current.push(callback);
};
};
export default useHistoryUpdate;
+33
View File
@@ -0,0 +1,33 @@
import { Dispatch, SetStateAction, useEffect, useState } from 'react';
export type UseLocalStorage = <S>(
key: string,
initialState: S | (() => S),
// If initialState is different from the initial local data, set it
initialValue?: S
) => [S, Dispatch<SetStateAction<S>>];
export const useLocalStorage: UseLocalStorage = (
key,
defaultValue,
initialValue
) => {
const [item, setItem] = useState(defaultValue);
useEffect(() => {
const saved = localStorage.getItem(key);
if (saved) {
setItem(JSON.parse(saved));
} else if (initialValue) {
setItem(initialValue);
}
}, [initialValue, key, setItem]);
useEffect(() => {
localStorage.setItem(key, JSON.stringify(item));
}, [item, key]);
return [item, setItem];
};
export default useLocalStorage;
+51
View File
@@ -0,0 +1,51 @@
import { useCallback, useEffect, useState } from 'react';
import { Member } from '@affine/datacenter';
import { useAppState } from '@/providers/app-state-provider';
export const useMembers = () => {
const { dataCenter, currentWorkspace } = useAppState();
const [members, setMembers] = useState<Member[]>([]);
const [loaded, setLoaded] = useState(false);
const refreshMembers = useCallback(async () => {
if (!currentWorkspace || !dataCenter) return;
const members = await dataCenter.getMembers(currentWorkspace.id);
setMembers(members);
}, [dataCenter, currentWorkspace]);
useEffect(() => {
const init = async () => {
await refreshMembers();
setLoaded(true);
};
init();
}, [refreshMembers]);
const inviteMember = async (email: string) => {
currentWorkspace &&
dataCenter &&
(await dataCenter.inviteMember(currentWorkspace.id, email));
};
const removeMember = async (permissionId: number) => {
if (!currentWorkspace || !dataCenter) {
return;
}
setLoaded(false);
await dataCenter.removeMember(currentWorkspace.id, permissionId);
await refreshMembers();
setLoaded(true);
};
const getUserByEmail = async (email: string) => {
if (!currentWorkspace) return null;
return dataCenter?.getUserByEmail(currentWorkspace.id, email);
};
return {
members,
removeMember,
inviteMember,
getUserByEmail,
loaded,
};
};
export default useMembers;
+144
View File
@@ -0,0 +1,144 @@
import { uuidv4, Workspace } from '@blocksuite/store';
import { QueryContent } from '@blocksuite/store/dist/workspace/search';
import { PageMeta, useAppState } from '@/providers/app-state-provider';
import { EditorContainer } from '@blocksuite/editor';
import { useChangePageMeta } from '@/hooks/use-change-page-meta';
import { useRouter } from 'next/router';
import { WorkspaceUnit } from '@affine/datacenter';
export type EditorHandlers = {
createPage: (params?: {
pageId?: string;
title?: string;
}) => Promise<string | null>;
openPage: (
pageId: string,
query?: { [key: string]: string },
newTab?: boolean
) => Promise<boolean>;
getPageMeta: (pageId: string) => PageMeta | null;
toggleDeletePage: (pageId: string) => Promise<boolean>;
toggleFavoritePage: (pageId: string) => Promise<boolean>;
permanentlyDeletePage: (pageId: string) => void;
search: (
query: QueryContent,
workspace?: Workspace
) => Map<string, string | undefined>;
// changeEditorMode: (pageId: string) => void;
changePageMode: (
pageId: string,
mode: EditorContainer['mode']
) => Promise<EditorContainer['mode']>;
};
const getPageMeta = (workspace: WorkspaceUnit | null, pageId: string) => {
return workspace?.blocksuiteWorkspace?.meta.pageMetas.find(
p => p.id === pageId
);
};
export const usePageHelper = (): EditorHandlers => {
const router = useRouter();
const changePageMeta = useChangePageMeta();
const { currentWorkspace, editor } = useAppState();
return {
createPage: ({
pageId = uuidv4().replaceAll('-', ''),
title = '',
} = {}) => {
return new Promise(resolve => {
if (!currentWorkspace) {
return resolve(null);
}
currentWorkspace.blocksuiteWorkspace?.createPage(pageId);
currentWorkspace.blocksuiteWorkspace?.signals.pageAdded.once(
addedPageId => {
currentWorkspace.blocksuiteWorkspace?.setPageMeta(addedPageId, {
title,
});
resolve(addedPageId);
}
);
});
},
toggleFavoritePage: async pageId => {
const pageMeta = getPageMeta(currentWorkspace, pageId);
if (!pageMeta) {
return Promise.reject('No page');
}
const favorite = !pageMeta.favorite;
changePageMeta(pageMeta.id, {
favorite,
});
return favorite;
},
toggleDeletePage: async pageId => {
const pageMeta = getPageMeta(currentWorkspace, pageId);
if (!pageMeta) {
return Promise.reject('No page');
}
const trash = !pageMeta.trash;
changePageMeta(pageMeta.id, {
trash,
trashDate: +new Date(),
});
return trash;
},
search: (query: QueryContent, workspace?: Workspace) => {
if (workspace) {
return workspace.search(query);
}
if (currentWorkspace) {
if (currentWorkspace.blocksuiteWorkspace) {
return currentWorkspace.blocksuiteWorkspace.search(query);
}
}
return new Map();
},
changePageMode: async (pageId, mode) => {
const pageMeta = getPageMeta(currentWorkspace, pageId);
if (!pageMeta) {
return Promise.reject('No page');
}
editor?.setAttribute('mode', mode as string);
changePageMeta(pageMeta.id, {
mode,
});
return mode;
},
permanentlyDeletePage: pageId => {
// TODO: workspace.meta.removePage or workspace.removePage?
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
currentWorkspace!.blocksuiteWorkspace?.meta.removePage(pageId);
},
openPage: (pageId, query = {}, newTab = false) => {
pageId = pageId.replace('space:', '');
if (newTab) {
window.open(`/workspace/${currentWorkspace?.id}/${pageId}`, '_blank');
return Promise.resolve(true);
}
return router.push({
pathname: `/workspace/${currentWorkspace?.id}/${pageId}`,
query,
});
},
getPageMeta: pageId => {
if (!currentWorkspace) {
return null;
}
return (
(currentWorkspace.blocksuiteWorkspace?.meta.pageMetas.find(
page => page.id === pageId
) as PageMeta) || null
);
},
};
};
export default usePageHelper;
+38
View File
@@ -0,0 +1,38 @@
import { useEffect, useRef } from 'react';
import { EditorContainer } from '@blocksuite/editor';
import { useAppState } from '@/providers/app-state-provider';
export type EventCallBack<T> = (callback: (props: T) => void) => void;
export type UsePropsUpdated = (
editor?: EditorContainer
) => EventCallBack<EditorContainer>;
export const usePropsUpdated: UsePropsUpdated = () => {
const { editor } = useAppState();
const callbackQueue = useRef<((editor: EditorContainer) => void)[]>([]);
useEffect(() => {
if (!editor) {
return;
}
setTimeout(() => {
editor.pageBlockModel?.propsUpdated.on(() => {
callbackQueue.current.forEach(callback => {
callback(editor);
});
});
}, 300);
return () => {
callbackQueue.current = [];
editor?.pageBlockModel?.propsUpdated?.dispose();
};
}, [editor]);
return callback => {
callbackQueue.current.push(callback);
};
};
export default usePropsUpdated;
@@ -0,0 +1,58 @@
import { useAppState } from '@/providers/app-state-provider';
import { WorkspaceUnit } from '@affine/datacenter';
export const useWorkspaceHelper = () => {
const { dataCenter, currentWorkspace } = useAppState();
const createWorkspace = async (name: string) => {
const workspaceInfo = await dataCenter.createWorkspace({
name: name,
});
if (workspaceInfo && workspaceInfo.id) {
return await dataCenter.loadWorkspace(workspaceInfo.id);
}
return null;
};
// const updateWorkspace = async (workspace: Workspace) => {};
const publishWorkspace = async (workspaceId: string, publish: boolean) => {
await dataCenter.setWorkspacePublish(workspaceId, publish);
};
const updateWorkspace = async (
{ name, avatarBlob }: { name?: string; avatarBlob?: Blob },
workspace: WorkspaceUnit
) => {
if (name) {
await dataCenter.updateWorkspaceMeta({ name }, workspace);
}
if (avatarBlob) {
const blobId = await dataCenter.setBlob(workspace, avatarBlob);
await dataCenter.updateWorkspaceMeta({ avatar: blobId }, workspace);
}
};
const deleteWorkSpace = async () => {
currentWorkspace && (await dataCenter.deleteWorkspace(currentWorkspace.id));
};
const leaveWorkSpace = async () => {
currentWorkspace && (await dataCenter.leaveWorkspace(currentWorkspace.id));
};
const acceptInvite = async (inviteCode: string) => {
let inviteInfo;
if (inviteCode) {
inviteInfo = await dataCenter.acceptInvitation(inviteCode);
}
return inviteInfo;
};
return {
createWorkspace,
publishWorkspace,
updateWorkspace,
deleteWorkSpace,
leaveWorkSpace,
acceptInvite,
};
};