Skip to content

Commit 827f478

Browse files
authored
[PE-238] refactor: page store hooks (#6409)
* refactor: page store hooks * fix: page details instances * fix: build errors * refactor: page store hooks * fix: minor bug
1 parent dd11ebf commit 827f478

File tree

30 files changed

+216
-103
lines changed

30 files changed

+216
-103
lines changed

web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(detail)/[pageId]/page.tsx

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ import { IssuePeekOverview } from "@/components/issues";
1919
import { PageRoot, TPageRootConfig, TPageRootHandlers } from "@/components/pages";
2020
// hooks
2121
import { useEditorConfig } from "@/hooks/editor";
22-
import { useEditorAsset, useProjectPage, useProjectPages, useWorkspace } from "@/hooks/store";
22+
import { useEditorAsset, useWorkspace } from "@/hooks/store";
23+
// plane web hooks
24+
import { EPageStoreType, usePage, usePageStore } from "@/plane-web/hooks/store";
2325
// plane web services
2426
import { WorkspaceService } from "@/plane-web/services";
2527
// services
@@ -31,13 +33,16 @@ const projectPageVersionService = new ProjectPageVersionService();
3133
const PageDetailsPage = observer(() => {
3234
const { workspaceSlug, projectId, pageId } = useParams();
3335
// store hooks
34-
const { createPage, getPageById } = useProjectPages();
35-
const page = useProjectPage(pageId?.toString() ?? "");
36+
const { createPage, fetchPageDetails } = usePageStore(EPageStoreType.PROJECT);
37+
const page = usePage({
38+
pageId: pageId?.toString() ?? "",
39+
storeType: EPageStoreType.PROJECT,
40+
});
3641
const { getWorkspaceBySlug } = useWorkspace();
3742
const { uploadEditorAsset } = useEditorAsset();
3843
// derived values
3944
const workspaceId = workspaceSlug ? (getWorkspaceBySlug(workspaceSlug.toString())?.id ?? "") : "";
40-
const { canCurrentUserAccessPage, id, name, updateDescription } = page;
45+
const { canCurrentUserAccessPage, id, name, updateDescription } = page ?? {};
4146
// entity search handler
4247
const fetchEntityCallback = useCallback(
4348
async (payload: TSearchEntityRequestPayload) =>
@@ -53,7 +58,7 @@ const PageDetailsPage = observer(() => {
5358
const { error: pageDetailsError } = useSWR(
5459
workspaceSlug && projectId && pageId ? `PAGE_DETAILS_${pageId}` : null,
5560
workspaceSlug && projectId && pageId
56-
? () => getPageById(workspaceSlug?.toString(), projectId?.toString(), pageId.toString())
61+
? () => fetchPageDetails(workspaceSlug?.toString(), projectId?.toString(), pageId.toString())
5762
: null,
5863
{
5964
revalidateIfStale: true,
@@ -70,8 +75,8 @@ const PageDetailsPage = observer(() => {
7075
return await projectPageVersionService.fetchAllVersions(workspaceSlug.toString(), projectId.toString(), pageId);
7176
},
7277
fetchDescriptionBinary: async () => {
73-
if (!workspaceSlug || !projectId || !page.id) return;
74-
return await projectPageService.fetchDescriptionBinary(workspaceSlug.toString(), projectId.toString(), page.id);
78+
if (!workspaceSlug || !projectId || !id) return;
79+
return await projectPageService.fetchDescriptionBinary(workspaceSlug.toString(), projectId.toString(), id);
7580
},
7681
fetchEntity: fetchEntityCallback,
7782
fetchVersionDetails: async (pageId, versionId) => {
@@ -84,9 +89,9 @@ const PageDetailsPage = observer(() => {
8489
);
8590
},
8691
getRedirectionLink: (pageId) => `/${workspaceSlug}/projects/${projectId}/pages/${pageId}`,
87-
updateDescription,
92+
updateDescription: updateDescription ?? (async () => {}),
8893
}),
89-
[createPage, fetchEntityCallback, page.id, projectId, updateDescription, workspaceSlug]
94+
[createPage, fetchEntityCallback, id, projectId, updateDescription, workspaceSlug]
9095
);
9196
// page root config
9297
const pageRootConfig: TPageRootConfig = useMemo(
@@ -145,6 +150,8 @@ const PageDetailsPage = observer(() => {
145150
</div>
146151
);
147152

153+
if (!page) return null;
154+
148155
return (
149156
<>
150157
<PageHead title={name} />
@@ -154,6 +161,7 @@ const PageDetailsPage = observer(() => {
154161
config={pageRootConfig}
155162
handlers={pageRootHandlers}
156163
page={page}
164+
storeType={EPageStoreType.PROJECT}
157165
webhookConnectionParams={webhookConnectionParams}
158166
workspaceSlug={workspaceSlug?.toString() ?? ""}
159167
/>

web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(detail)/header.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@ import { PageEditInformationPopover } from "@/components/pages";
1515
import { convertHexEmojiToDecimal } from "@/helpers/emoji.helper";
1616
import { getPageName } from "@/helpers/page.helper";
1717
// hooks
18-
import { useProjectPage, useProject } from "@/hooks/store";
18+
import { useProject } from "@/hooks/store";
1919
import { usePlatformOS } from "@/hooks/use-platform-os";
2020
// plane web components
2121
import { ProjectBreadcrumb } from "@/plane-web/components/breadcrumbs";
2222
import { PageDetailsHeaderExtraActions } from "@/plane-web/components/pages";
23+
// plane web hooks
24+
import { EPageStoreType, usePage } from "@/plane-web/hooks/store";
2325

2426
export interface IPagesHeaderProps {
2527
showButton?: boolean;
@@ -32,7 +34,12 @@ export const PageDetailsHeader = observer(() => {
3234
const [isOpen, setIsOpen] = useState(false);
3335
// store hooks
3436
const { currentProjectDetails, loader } = useProject();
35-
const page = useProjectPage(pageId?.toString() ?? "");
37+
const page = usePage({
38+
pageId: pageId?.toString() ?? "",
39+
storeType: EPageStoreType.PROJECT,
40+
});
41+
if (!page) return null;
42+
// derived values
3643
const { name, logo_props, updatePageLogo, isContentEditable } = page;
3744
// use platform
3845
const { isMobile } = usePlatformOS();

web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(list)/header.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@ import { Breadcrumbs, Button, Header, setToast, TOAST_TYPE } from "@plane/ui";
1313
// helpers
1414
import { BreadcrumbLink } from "@/components/common";
1515
// hooks
16-
import { useEventTracker, useProject, useProjectPages } from "@/hooks/store";
16+
import { useEventTracker, useProject } from "@/hooks/store";
1717
// plane web
1818
import { ProjectBreadcrumb } from "@/plane-web/components/breadcrumbs";
19+
// plane web hooks
20+
import { EPageStoreType, usePageStore } from "@/plane-web/hooks/store";
1921

2022
export const PagesListHeader = observer(() => {
2123
// states
@@ -27,7 +29,7 @@ export const PagesListHeader = observer(() => {
2729
const pageType = searchParams.get("type");
2830
// store hooks
2931
const { currentProjectDetails, loader } = useProject();
30-
const { canCurrentUserCreatePage, createPage } = useProjectPages();
32+
const { canCurrentUserCreatePage, createPage } = usePageStore(EPageStoreType.PROJECT);
3133
const { setTrackElement } = useEventTracker();
3234
// handle page create
3335
const handleCreatePage = async () => {

web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(list)/page.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import { PagesListRoot, PagesListView } from "@/components/pages";
1414
import { useProject, useUserPermissions } from "@/hooks/store";
1515
import { useAppRouter } from "@/hooks/use-app-router";
1616
import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path";
17+
// plane web hooks
18+
import { EPageStoreType } from "@/plane-web/hooks/store";
1719

1820
const ProjectPagesPage = observer(() => {
1921
// router
@@ -63,11 +65,12 @@ const ProjectPagesPage = observer(() => {
6365
<>
6466
<PageHead title={pageTitle} />
6567
<PagesListView
66-
workspaceSlug={workspaceSlug.toString()}
67-
projectId={projectId.toString()}
6868
pageType={currentPageType()}
69+
projectId={projectId.toString()}
70+
storeType={EPageStoreType.PROJECT}
71+
workspaceSlug={workspaceSlug.toString()}
6972
>
70-
<PagesListRoot pageType={currentPageType()} />
73+
<PagesListRoot pageType={currentPageType()} storeType={EPageStoreType.PROJECT} />
7174
</PagesListView>
7275
</>
7376
);

web/ce/components/command-palette/modals/project-level.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import { CreatePageModal } from "@/components/pages";
66
import { CreateUpdateProjectViewModal } from "@/components/views";
77
// hooks
88
import { useCommandPalette } from "@/hooks/store";
9+
// plane web hooks
10+
import { EPageStoreType } from "@/plane-web/hooks/store";
911

1012
export type TProjectLevelModalsProps = {
1113
workspaceSlug: string;
@@ -53,6 +55,7 @@ export const ProjectLevelModals = observer((props: TProjectLevelModalsProps) =>
5355
pageAccess={createPageModal.pageAccess}
5456
handleModalClose={() => toggleCreatePageModal({ isOpen: false })}
5557
redirectionEnabled
58+
storeType={EPageStoreType.PROJECT}
5659
/>
5760
</>
5861
);

web/ce/hooks/store/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from "./use-page-store";
2+
export * from "./use-page";
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { useContext } from "react";
2+
// context
3+
import { StoreContext } from "@/lib/store-context";
4+
// mobx store
5+
import { IProjectPageStore } from "@/store/pages/project-page.store";
6+
7+
export enum EPageStoreType {
8+
PROJECT = "PROJECT_PAGE",
9+
}
10+
11+
export type TReturnType = {
12+
[EPageStoreType.PROJECT]: IProjectPageStore;
13+
};
14+
15+
export const usePageStore = <T extends EPageStoreType>(storeType: T): TReturnType[T] => {
16+
const context = useContext(StoreContext);
17+
if (context === undefined) throw new Error("usePageStore must be used within StoreProvider");
18+
19+
if (storeType === EPageStoreType.PROJECT) {
20+
return context.projectPages;
21+
}
22+
23+
throw new Error(`Invalid store type: ${storeType}`);
24+
};

web/ce/hooks/store/use-page.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { useContext } from "react";
2+
// mobx store
3+
import { StoreContext } from "@/lib/store-context";
4+
// plane web hooks
5+
import { EPageStoreType, usePageStore } from "@/plane-web/hooks/store";
6+
7+
export type TArgs = {
8+
pageId: string;
9+
storeType: EPageStoreType;
10+
};
11+
12+
export const usePage = (args: TArgs) => {
13+
const { pageId, storeType } = args;
14+
// context
15+
const context = useContext(StoreContext);
16+
// store hooks
17+
const pageStore = usePageStore(storeType);
18+
19+
if (context === undefined) throw new Error("usePage must be used within StoreProvider");
20+
if (!pageId) throw new Error("pageId is required");
21+
22+
return pageStore.getPageById(pageId);
23+
};

web/core/components/pages/dropdowns/actions.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import { usePageOperations } from "@/hooks/use-page-operations";
3030
// plane web components
3131
import { MovePageModal } from "@/plane-web/components/pages";
3232
// plane web hooks
33+
import { EPageStoreType } from "@/plane-web/hooks/store";
3334
import { usePageFlag } from "@/plane-web/hooks/use-page-flag";
3435
// store types
3536
import { TPageInstance } from "@/store/pages/base-page";
@@ -55,10 +56,11 @@ type Props = {
5556
optionsOrder: TPageActions[];
5657
page: TPageInstance;
5758
parentRef?: React.RefObject<HTMLElement>;
59+
storeType: EPageStoreType;
5860
};
5961

6062
export const PageActions: React.FC<Props> = observer((props) => {
61-
const { editorRef, extraOptions, optionsOrder, page, parentRef } = props;
63+
const { editorRef, extraOptions, optionsOrder, page, parentRef, storeType } = props;
6264
// states
6365
const [deletePageModal, setDeletePageModal] = useState(false);
6466
const [movePageModal, setMovePageModal] = useState(false);
@@ -175,7 +177,12 @@ export const PageActions: React.FC<Props> = observer((props) => {
175177
return (
176178
<>
177179
<MovePageModal isOpen={movePageModal} onClose={() => setMovePageModal(false)} page={page} />
178-
<DeletePageModal isOpen={deletePageModal} onClose={() => setDeletePageModal(false)} page={page} />
180+
<DeletePageModal
181+
isOpen={deletePageModal}
182+
onClose={() => setDeletePageModal(false)}
183+
page={page}
184+
storeType={storeType}
185+
/>
179186
{parentRef && <ContextMenu parentRef={parentRef} items={arrangedOptions} />}
180187
<CustomMenu placement="bottom-end" optionsClassName="max-h-[90vh]" ellipsis closeOnSelect>
181188
{arrangedOptions.map((item) => {

web/core/components/pages/editor/header/extra-options.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,19 @@ import { PageInfoPopover, PageOptionsDropdown } from "@/components/pages";
1212
import { renderFormattedDate } from "@/helpers/date-time.helper";
1313
// hooks
1414
import useOnlineStatus from "@/hooks/use-online-status";
15+
// plane web hooks
16+
import { EPageStoreType } from "@/plane-web/hooks/store";
1517
// store
1618
import { TPageInstance } from "@/store/pages/base-page";
1719

1820
type Props = {
1921
editorRef: EditorRefApi;
2022
page: TPageInstance;
23+
storeType: EPageStoreType;
2124
};
2225

2326
export const PageExtraOptions: React.FC<Props> = observer((props) => {
24-
const { editorRef, page } = props;
27+
const { editorRef, page, storeType } = props;
2528
// derived values
2629
const {
2730
archived_at,
@@ -84,7 +87,7 @@ export const PageExtraOptions: React.FC<Props> = observer((props) => {
8487
/>
8588
)}
8689
<PageInfoPopover editorRef={editorRef} page={page} />
87-
<PageOptionsDropdown editorRef={editorRef} page={page} />
90+
<PageOptionsDropdown editorRef={editorRef} page={page} storeType={storeType} />
8891
</div>
8992
);
9093
});

0 commit comments

Comments
 (0)