[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
This commit is contained in:
parent
dd11ebf335
commit
827f47809b
30 changed files with 216 additions and 103 deletions
|
|
@ -19,7 +19,9 @@ import { IssuePeekOverview } from "@/components/issues";
|
|||
import { PageRoot, TPageRootConfig, TPageRootHandlers } from "@/components/pages";
|
||||
// hooks
|
||||
import { useEditorConfig } from "@/hooks/editor";
|
||||
import { useEditorAsset, useProjectPage, useProjectPages, useWorkspace } from "@/hooks/store";
|
||||
import { useEditorAsset, useWorkspace } from "@/hooks/store";
|
||||
// plane web hooks
|
||||
import { EPageStoreType, usePage, usePageStore } from "@/plane-web/hooks/store";
|
||||
// plane web services
|
||||
import { WorkspaceService } from "@/plane-web/services";
|
||||
// services
|
||||
|
|
@ -31,13 +33,16 @@ const projectPageVersionService = new ProjectPageVersionService();
|
|||
const PageDetailsPage = observer(() => {
|
||||
const { workspaceSlug, projectId, pageId } = useParams();
|
||||
// store hooks
|
||||
const { createPage, getPageById } = useProjectPages();
|
||||
const page = useProjectPage(pageId?.toString() ?? "");
|
||||
const { createPage, fetchPageDetails } = usePageStore(EPageStoreType.PROJECT);
|
||||
const page = usePage({
|
||||
pageId: pageId?.toString() ?? "",
|
||||
storeType: EPageStoreType.PROJECT,
|
||||
});
|
||||
const { getWorkspaceBySlug } = useWorkspace();
|
||||
const { uploadEditorAsset } = useEditorAsset();
|
||||
// derived values
|
||||
const workspaceId = workspaceSlug ? (getWorkspaceBySlug(workspaceSlug.toString())?.id ?? "") : "";
|
||||
const { canCurrentUserAccessPage, id, name, updateDescription } = page;
|
||||
const { canCurrentUserAccessPage, id, name, updateDescription } = page ?? {};
|
||||
// entity search handler
|
||||
const fetchEntityCallback = useCallback(
|
||||
async (payload: TSearchEntityRequestPayload) =>
|
||||
|
|
@ -53,7 +58,7 @@ const PageDetailsPage = observer(() => {
|
|||
const { error: pageDetailsError } = useSWR(
|
||||
workspaceSlug && projectId && pageId ? `PAGE_DETAILS_${pageId}` : null,
|
||||
workspaceSlug && projectId && pageId
|
||||
? () => getPageById(workspaceSlug?.toString(), projectId?.toString(), pageId.toString())
|
||||
? () => fetchPageDetails(workspaceSlug?.toString(), projectId?.toString(), pageId.toString())
|
||||
: null,
|
||||
{
|
||||
revalidateIfStale: true,
|
||||
|
|
@ -70,8 +75,8 @@ const PageDetailsPage = observer(() => {
|
|||
return await projectPageVersionService.fetchAllVersions(workspaceSlug.toString(), projectId.toString(), pageId);
|
||||
},
|
||||
fetchDescriptionBinary: async () => {
|
||||
if (!workspaceSlug || !projectId || !page.id) return;
|
||||
return await projectPageService.fetchDescriptionBinary(workspaceSlug.toString(), projectId.toString(), page.id);
|
||||
if (!workspaceSlug || !projectId || !id) return;
|
||||
return await projectPageService.fetchDescriptionBinary(workspaceSlug.toString(), projectId.toString(), id);
|
||||
},
|
||||
fetchEntity: fetchEntityCallback,
|
||||
fetchVersionDetails: async (pageId, versionId) => {
|
||||
|
|
@ -84,9 +89,9 @@ const PageDetailsPage = observer(() => {
|
|||
);
|
||||
},
|
||||
getRedirectionLink: (pageId) => `/${workspaceSlug}/projects/${projectId}/pages/${pageId}`,
|
||||
updateDescription,
|
||||
updateDescription: updateDescription ?? (async () => {}),
|
||||
}),
|
||||
[createPage, fetchEntityCallback, page.id, projectId, updateDescription, workspaceSlug]
|
||||
[createPage, fetchEntityCallback, id, projectId, updateDescription, workspaceSlug]
|
||||
);
|
||||
// page root config
|
||||
const pageRootConfig: TPageRootConfig = useMemo(
|
||||
|
|
@ -145,6 +150,8 @@ const PageDetailsPage = observer(() => {
|
|||
</div>
|
||||
);
|
||||
|
||||
if (!page) return null;
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageHead title={name} />
|
||||
|
|
@ -154,6 +161,7 @@ const PageDetailsPage = observer(() => {
|
|||
config={pageRootConfig}
|
||||
handlers={pageRootHandlers}
|
||||
page={page}
|
||||
storeType={EPageStoreType.PROJECT}
|
||||
webhookConnectionParams={webhookConnectionParams}
|
||||
workspaceSlug={workspaceSlug?.toString() ?? ""}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -15,11 +15,13 @@ import { PageEditInformationPopover } from "@/components/pages";
|
|||
import { convertHexEmojiToDecimal } from "@/helpers/emoji.helper";
|
||||
import { getPageName } from "@/helpers/page.helper";
|
||||
// hooks
|
||||
import { useProjectPage, useProject } from "@/hooks/store";
|
||||
import { useProject } from "@/hooks/store";
|
||||
import { usePlatformOS } from "@/hooks/use-platform-os";
|
||||
// plane web components
|
||||
import { ProjectBreadcrumb } from "@/plane-web/components/breadcrumbs";
|
||||
import { PageDetailsHeaderExtraActions } from "@/plane-web/components/pages";
|
||||
// plane web hooks
|
||||
import { EPageStoreType, usePage } from "@/plane-web/hooks/store";
|
||||
|
||||
export interface IPagesHeaderProps {
|
||||
showButton?: boolean;
|
||||
|
|
@ -32,7 +34,12 @@ export const PageDetailsHeader = observer(() => {
|
|||
const [isOpen, setIsOpen] = useState(false);
|
||||
// store hooks
|
||||
const { currentProjectDetails, loader } = useProject();
|
||||
const page = useProjectPage(pageId?.toString() ?? "");
|
||||
const page = usePage({
|
||||
pageId: pageId?.toString() ?? "",
|
||||
storeType: EPageStoreType.PROJECT,
|
||||
});
|
||||
if (!page) return null;
|
||||
// derived values
|
||||
const { name, logo_props, updatePageLogo, isContentEditable } = page;
|
||||
// use platform
|
||||
const { isMobile } = usePlatformOS();
|
||||
|
|
|
|||
|
|
@ -13,9 +13,11 @@ import { Breadcrumbs, Button, Header, setToast, TOAST_TYPE } from "@plane/ui";
|
|||
// helpers
|
||||
import { BreadcrumbLink } from "@/components/common";
|
||||
// hooks
|
||||
import { useEventTracker, useProject, useProjectPages } from "@/hooks/store";
|
||||
import { useEventTracker, useProject } from "@/hooks/store";
|
||||
// plane web
|
||||
import { ProjectBreadcrumb } from "@/plane-web/components/breadcrumbs";
|
||||
// plane web hooks
|
||||
import { EPageStoreType, usePageStore } from "@/plane-web/hooks/store";
|
||||
|
||||
export const PagesListHeader = observer(() => {
|
||||
// states
|
||||
|
|
@ -27,7 +29,7 @@ export const PagesListHeader = observer(() => {
|
|||
const pageType = searchParams.get("type");
|
||||
// store hooks
|
||||
const { currentProjectDetails, loader } = useProject();
|
||||
const { canCurrentUserCreatePage, createPage } = useProjectPages();
|
||||
const { canCurrentUserCreatePage, createPage } = usePageStore(EPageStoreType.PROJECT);
|
||||
const { setTrackElement } = useEventTracker();
|
||||
// handle page create
|
||||
const handleCreatePage = async () => {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ import { PagesListRoot, PagesListView } from "@/components/pages";
|
|||
import { useProject, useUserPermissions } from "@/hooks/store";
|
||||
import { useAppRouter } from "@/hooks/use-app-router";
|
||||
import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path";
|
||||
// plane web hooks
|
||||
import { EPageStoreType } from "@/plane-web/hooks/store";
|
||||
|
||||
const ProjectPagesPage = observer(() => {
|
||||
// router
|
||||
|
|
@ -63,11 +65,12 @@ const ProjectPagesPage = observer(() => {
|
|||
<>
|
||||
<PageHead title={pageTitle} />
|
||||
<PagesListView
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
projectId={projectId.toString()}
|
||||
pageType={currentPageType()}
|
||||
projectId={projectId.toString()}
|
||||
storeType={EPageStoreType.PROJECT}
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
>
|
||||
<PagesListRoot pageType={currentPageType()} />
|
||||
<PagesListRoot pageType={currentPageType()} storeType={EPageStoreType.PROJECT} />
|
||||
</PagesListView>
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import { CreatePageModal } from "@/components/pages";
|
|||
import { CreateUpdateProjectViewModal } from "@/components/views";
|
||||
// hooks
|
||||
import { useCommandPalette } from "@/hooks/store";
|
||||
// plane web hooks
|
||||
import { EPageStoreType } from "@/plane-web/hooks/store";
|
||||
|
||||
export type TProjectLevelModalsProps = {
|
||||
workspaceSlug: string;
|
||||
|
|
@ -53,6 +55,7 @@ export const ProjectLevelModals = observer((props: TProjectLevelModalsProps) =>
|
|||
pageAccess={createPageModal.pageAccess}
|
||||
handleModalClose={() => toggleCreatePageModal({ isOpen: false })}
|
||||
redirectionEnabled
|
||||
storeType={EPageStoreType.PROJECT}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
2
web/ce/hooks/store/index.ts
Normal file
2
web/ce/hooks/store/index.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export * from "./use-page-store";
|
||||
export * from "./use-page";
|
||||
24
web/ce/hooks/store/use-page-store.ts
Normal file
24
web/ce/hooks/store/use-page-store.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import { useContext } from "react";
|
||||
// context
|
||||
import { StoreContext } from "@/lib/store-context";
|
||||
// mobx store
|
||||
import { IProjectPageStore } from "@/store/pages/project-page.store";
|
||||
|
||||
export enum EPageStoreType {
|
||||
PROJECT = "PROJECT_PAGE",
|
||||
}
|
||||
|
||||
export type TReturnType = {
|
||||
[EPageStoreType.PROJECT]: IProjectPageStore;
|
||||
};
|
||||
|
||||
export const usePageStore = <T extends EPageStoreType>(storeType: T): TReturnType[T] => {
|
||||
const context = useContext(StoreContext);
|
||||
if (context === undefined) throw new Error("usePageStore must be used within StoreProvider");
|
||||
|
||||
if (storeType === EPageStoreType.PROJECT) {
|
||||
return context.projectPages;
|
||||
}
|
||||
|
||||
throw new Error(`Invalid store type: ${storeType}`);
|
||||
};
|
||||
23
web/ce/hooks/store/use-page.ts
Normal file
23
web/ce/hooks/store/use-page.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { useContext } from "react";
|
||||
// mobx store
|
||||
import { StoreContext } from "@/lib/store-context";
|
||||
// plane web hooks
|
||||
import { EPageStoreType, usePageStore } from "@/plane-web/hooks/store";
|
||||
|
||||
export type TArgs = {
|
||||
pageId: string;
|
||||
storeType: EPageStoreType;
|
||||
};
|
||||
|
||||
export const usePage = (args: TArgs) => {
|
||||
const { pageId, storeType } = args;
|
||||
// context
|
||||
const context = useContext(StoreContext);
|
||||
// store hooks
|
||||
const pageStore = usePageStore(storeType);
|
||||
|
||||
if (context === undefined) throw new Error("usePage must be used within StoreProvider");
|
||||
if (!pageId) throw new Error("pageId is required");
|
||||
|
||||
return pageStore.getPageById(pageId);
|
||||
};
|
||||
|
|
@ -30,6 +30,7 @@ import { usePageOperations } from "@/hooks/use-page-operations";
|
|||
// plane web components
|
||||
import { MovePageModal } from "@/plane-web/components/pages";
|
||||
// plane web hooks
|
||||
import { EPageStoreType } from "@/plane-web/hooks/store";
|
||||
import { usePageFlag } from "@/plane-web/hooks/use-page-flag";
|
||||
// store types
|
||||
import { TPageInstance } from "@/store/pages/base-page";
|
||||
|
|
@ -55,10 +56,11 @@ type Props = {
|
|||
optionsOrder: TPageActions[];
|
||||
page: TPageInstance;
|
||||
parentRef?: React.RefObject<HTMLElement>;
|
||||
storeType: EPageStoreType;
|
||||
};
|
||||
|
||||
export const PageActions: React.FC<Props> = observer((props) => {
|
||||
const { editorRef, extraOptions, optionsOrder, page, parentRef } = props;
|
||||
const { editorRef, extraOptions, optionsOrder, page, parentRef, storeType } = props;
|
||||
// states
|
||||
const [deletePageModal, setDeletePageModal] = useState(false);
|
||||
const [movePageModal, setMovePageModal] = useState(false);
|
||||
|
|
@ -175,7 +177,12 @@ export const PageActions: React.FC<Props> = observer((props) => {
|
|||
return (
|
||||
<>
|
||||
<MovePageModal isOpen={movePageModal} onClose={() => setMovePageModal(false)} page={page} />
|
||||
<DeletePageModal isOpen={deletePageModal} onClose={() => setDeletePageModal(false)} page={page} />
|
||||
<DeletePageModal
|
||||
isOpen={deletePageModal}
|
||||
onClose={() => setDeletePageModal(false)}
|
||||
page={page}
|
||||
storeType={storeType}
|
||||
/>
|
||||
{parentRef && <ContextMenu parentRef={parentRef} items={arrangedOptions} />}
|
||||
<CustomMenu placement="bottom-end" optionsClassName="max-h-[90vh]" ellipsis closeOnSelect>
|
||||
{arrangedOptions.map((item) => {
|
||||
|
|
|
|||
|
|
@ -12,16 +12,19 @@ import { PageInfoPopover, PageOptionsDropdown } from "@/components/pages";
|
|||
import { renderFormattedDate } from "@/helpers/date-time.helper";
|
||||
// hooks
|
||||
import useOnlineStatus from "@/hooks/use-online-status";
|
||||
// plane web hooks
|
||||
import { EPageStoreType } from "@/plane-web/hooks/store";
|
||||
// store
|
||||
import { TPageInstance } from "@/store/pages/base-page";
|
||||
|
||||
type Props = {
|
||||
editorRef: EditorRefApi;
|
||||
page: TPageInstance;
|
||||
storeType: EPageStoreType;
|
||||
};
|
||||
|
||||
export const PageExtraOptions: React.FC<Props> = observer((props) => {
|
||||
const { editorRef, page } = props;
|
||||
const { editorRef, page, storeType } = props;
|
||||
// derived values
|
||||
const {
|
||||
archived_at,
|
||||
|
|
@ -84,7 +87,7 @@ export const PageExtraOptions: React.FC<Props> = observer((props) => {
|
|||
/>
|
||||
)}
|
||||
<PageInfoPopover editorRef={editorRef} page={page} />
|
||||
<PageOptionsDropdown editorRef={editorRef} page={page} />
|
||||
<PageOptionsDropdown editorRef={editorRef} page={page} storeType={storeType} />
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import { Header, EHeaderVariant } from "@plane/ui";
|
|||
import { PageExtraOptions, PageSummaryPopover, PageToolbar } from "@/components/pages";
|
||||
// hooks
|
||||
import { usePageFilters } from "@/hooks/use-page-filters";
|
||||
// plane web hooks
|
||||
import { EPageStoreType } from "@/plane-web/hooks/store";
|
||||
// store
|
||||
import { TPageInstance } from "@/store/pages/base-page";
|
||||
|
||||
|
|
@ -13,10 +15,11 @@ type Props = {
|
|||
page: TPageInstance;
|
||||
setSidePeekVisible: (sidePeekState: boolean) => void;
|
||||
sidePeekVisible: boolean;
|
||||
storeType: EPageStoreType;
|
||||
};
|
||||
|
||||
export const PageEditorMobileHeaderRoot: React.FC<Props> = observer((props) => {
|
||||
const { editorRef, page, setSidePeekVisible, sidePeekVisible } = props;
|
||||
const { editorRef, page, setSidePeekVisible, sidePeekVisible, storeType } = props;
|
||||
// derived values
|
||||
const { isContentEditable } = page;
|
||||
// page filters
|
||||
|
|
@ -33,7 +36,7 @@ export const PageEditorMobileHeaderRoot: React.FC<Props> = observer((props) => {
|
|||
setSidePeekVisible={setSidePeekVisible}
|
||||
/>
|
||||
</div>
|
||||
<PageExtraOptions editorRef={editorRef} page={page} />
|
||||
<PageExtraOptions editorRef={editorRef} page={page} storeType={storeType} />
|
||||
</Header>
|
||||
<Header variant={EHeaderVariant.TERNARY}>
|
||||
{isContentEditable && editorRef && <PageToolbar editorRef={editorRef} />}
|
||||
|
|
|
|||
|
|
@ -15,16 +15,19 @@ import { copyTextToClipboard } from "@/helpers/string.helper";
|
|||
// hooks
|
||||
import { usePageFilters } from "@/hooks/use-page-filters";
|
||||
import { useQueryParams } from "@/hooks/use-query-params";
|
||||
// plane web hooks
|
||||
import { EPageStoreType } from "@/plane-web/hooks/store";
|
||||
// store
|
||||
import { TPageInstance } from "@/store/pages/base-page";
|
||||
|
||||
type Props = {
|
||||
editorRef: EditorRefApi | null;
|
||||
page: TPageInstance;
|
||||
storeType: EPageStoreType;
|
||||
};
|
||||
|
||||
export const PageOptionsDropdown: React.FC<Props> = observer((props) => {
|
||||
const { editorRef, page } = props;
|
||||
const { editorRef, page, storeType } = props;
|
||||
// states
|
||||
const [isExportModalOpen, setIsExportModalOpen] = useState(false);
|
||||
// router
|
||||
|
|
@ -136,6 +139,7 @@ export const PageOptionsDropdown: React.FC<Props> = observer((props) => {
|
|||
"export",
|
||||
]}
|
||||
page={page}
|
||||
storeType={storeType}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import { PageEditorMobileHeaderRoot, PageExtraOptions, PageSummaryPopover, PageT
|
|||
import { cn } from "@/helpers/common.helper";
|
||||
// hooks
|
||||
import { usePageFilters } from "@/hooks/use-page-filters";
|
||||
// plane web hooks
|
||||
import { EPageStoreType } from "@/plane-web/hooks/store";
|
||||
// store
|
||||
import { TPageInstance } from "@/store/pages/base-page";
|
||||
|
||||
|
|
@ -16,10 +18,11 @@ type Props = {
|
|||
page: TPageInstance;
|
||||
setSidePeekVisible: (sidePeekState: boolean) => void;
|
||||
sidePeekVisible: boolean;
|
||||
storeType: EPageStoreType;
|
||||
};
|
||||
|
||||
export const PageEditorHeaderRoot: React.FC<Props> = observer((props) => {
|
||||
const { editorReady, editorRef, page, setSidePeekVisible, sidePeekVisible } = props;
|
||||
const { editorReady, editorRef, page, setSidePeekVisible, sidePeekVisible, storeType } = props;
|
||||
// derived values
|
||||
const { isContentEditable } = page;
|
||||
// page filters
|
||||
|
|
@ -52,7 +55,7 @@ export const PageEditorHeaderRoot: React.FC<Props> = observer((props) => {
|
|||
<PageToolbar editorRef={editorRef?.current} />
|
||||
)}
|
||||
</Header.LeftItem>
|
||||
<PageExtraOptions editorRef={resolvedEditorRef} page={page} />
|
||||
<PageExtraOptions editorRef={resolvedEditorRef} page={page} storeType={storeType} />
|
||||
</Header>
|
||||
<div className="md:hidden">
|
||||
<PageEditorMobileHeaderRoot
|
||||
|
|
@ -60,6 +63,7 @@ export const PageEditorHeaderRoot: React.FC<Props> = observer((props) => {
|
|||
page={page}
|
||||
sidePeekVisible={sidePeekVisible}
|
||||
setSidePeekVisible={setSidePeekVisible}
|
||||
storeType={storeType}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ import {
|
|||
import { useAppRouter } from "@/hooks/use-app-router";
|
||||
import { usePageFallback } from "@/hooks/use-page-fallback";
|
||||
import { useQueryParams } from "@/hooks/use-query-params";
|
||||
// plane web hooks
|
||||
import { EPageStoreType } from "@/plane-web/hooks/store";
|
||||
// store
|
||||
import { TPageInstance } from "@/store/pages/base-page";
|
||||
|
||||
|
|
@ -36,12 +38,13 @@ type TPageRootProps = {
|
|||
config: TPageRootConfig;
|
||||
handlers: TPageRootHandlers;
|
||||
page: TPageInstance;
|
||||
storeType: EPageStoreType;
|
||||
webhookConnectionParams: TWebhookConnectionQueryParams;
|
||||
workspaceSlug: string;
|
||||
};
|
||||
|
||||
export const PageRoot = observer((props: TPageRootProps) => {
|
||||
const { config, handlers, page, webhookConnectionParams, workspaceSlug } = props;
|
||||
const { config, handlers, page, storeType, webhookConnectionParams, workspaceSlug } = props;
|
||||
// states
|
||||
const [editorReady, setEditorReady] = useState(false);
|
||||
const [hasConnectionFailed, setHasConnectionFailed] = useState(false);
|
||||
|
|
@ -107,6 +110,7 @@ export const PageRoot = observer((props: TPageRootProps) => {
|
|||
page={page}
|
||||
setSidePeekVisible={(state) => setSidePeekVisible(state)}
|
||||
sidePeekVisible={sidePeekVisible}
|
||||
storeType={storeType}
|
||||
/>
|
||||
<PageEditorBody
|
||||
config={config}
|
||||
|
|
|
|||
|
|
@ -16,19 +16,22 @@ import {
|
|||
// helpers
|
||||
import { calculateTotalFilters } from "@/helpers/filter.helper";
|
||||
// hooks
|
||||
import { useMember, useProjectPages } from "@/hooks/store";
|
||||
import { useMember } from "@/hooks/store";
|
||||
// plane web hooks
|
||||
import { EPageStoreType, usePageStore } from "@/plane-web/hooks/store";
|
||||
|
||||
type Props = {
|
||||
pageType: TPageNavigationTabs;
|
||||
projectId: string;
|
||||
storeType: EPageStoreType;
|
||||
workspaceSlug: string;
|
||||
};
|
||||
|
||||
export const PagesListHeaderRoot: React.FC<Props> = observer((props) => {
|
||||
const { pageType, projectId, workspaceSlug } = props;
|
||||
const { pageType, projectId, storeType, workspaceSlug } = props;
|
||||
const { t } = useTranslation();
|
||||
// store hooks
|
||||
const { filters, updateFilters, clearAllFilters } = useProjectPages();
|
||||
const { filters, updateFilters, clearAllFilters } = usePageStore(storeType);
|
||||
const {
|
||||
workspace: { workspaceMemberIds },
|
||||
} = useMember();
|
||||
|
|
|
|||
|
|
@ -13,15 +13,19 @@ import { getFileURL } from "@/helpers/file.helper";
|
|||
// hooks
|
||||
import { useMember } from "@/hooks/store";
|
||||
import { usePageOperations } from "@/hooks/use-page-operations";
|
||||
// plane web hooks
|
||||
import { EPageStoreType } from "@/plane-web/hooks/store";
|
||||
// store
|
||||
import { TPageInstance } from "@/store/pages/base-page";
|
||||
|
||||
type Props = {
|
||||
page: TPageInstance;
|
||||
parentRef: React.RefObject<HTMLElement>;
|
||||
storeType: EPageStoreType;
|
||||
};
|
||||
|
||||
export const BlockItemAction: FC<Props> = observer((props) => {
|
||||
const { page, parentRef } = props;
|
||||
const { page, parentRef, storeType } = props;
|
||||
// store hooks
|
||||
const { getUserDetails } = useMember();
|
||||
// page operations
|
||||
|
|
@ -80,6 +84,7 @@ export const BlockItemAction: FC<Props> = observer((props) => {
|
|||
]}
|
||||
page={page}
|
||||
parentRef={parentRef}
|
||||
storeType={storeType}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -11,20 +11,26 @@ import { BlockItemAction } from "@/components/pages/list";
|
|||
import { getPageName } from "@/helpers/page.helper";
|
||||
// hooks
|
||||
import { usePlatformOS } from "@/hooks/use-platform-os";
|
||||
import { TUsePage } from "@/store/pages/base-page";
|
||||
// plane web hooks
|
||||
import { EPageStoreType, usePage } from "@/plane-web/hooks/store";
|
||||
|
||||
type TPageListBlock = {
|
||||
pageId: string;
|
||||
usePage: TUsePage;
|
||||
storeType: EPageStoreType;
|
||||
};
|
||||
|
||||
export const PageListBlock: FC<TPageListBlock> = observer((props) => {
|
||||
const { pageId, usePage } = props;
|
||||
const { pageId, storeType } = props;
|
||||
// refs
|
||||
const parentRef = useRef(null);
|
||||
// hooks
|
||||
const page = usePage(pageId);
|
||||
const page = usePage({
|
||||
pageId,
|
||||
storeType,
|
||||
});
|
||||
const { isMobile } = usePlatformOS();
|
||||
// handle page check
|
||||
if (!page) return null;
|
||||
// derived values
|
||||
const { name, logo_props, getRedirectionLink } = page;
|
||||
|
||||
|
|
@ -41,7 +47,7 @@ export const PageListBlock: FC<TPageListBlock> = observer((props) => {
|
|||
}
|
||||
title={getPageName(name)}
|
||||
itemLink={getRedirectionLink()}
|
||||
actionableItems={<BlockItemAction page={page} parentRef={parentRef} />}
|
||||
actionableItems={<BlockItemAction page={page} parentRef={parentRef} storeType={storeType} />}
|
||||
isMobile={isMobile}
|
||||
parentRef={parentRef}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -4,19 +4,20 @@ import { observer } from "mobx-react";
|
|||
import { TPageNavigationTabs } from "@plane/types";
|
||||
// components
|
||||
import { ListLayout } from "@/components/core/list";
|
||||
// hooks
|
||||
import { useProjectPage, useProjectPages } from "@/hooks/store";
|
||||
// plane web hooks
|
||||
import { EPageStoreType, usePageStore } from "@/plane-web/hooks/store";
|
||||
// components
|
||||
import { PageListBlock } from "./";
|
||||
|
||||
type TPagesListRoot = {
|
||||
pageType: TPageNavigationTabs;
|
||||
storeType: EPageStoreType;
|
||||
};
|
||||
|
||||
export const PagesListRoot: FC<TPagesListRoot> = observer((props) => {
|
||||
const { pageType } = props;
|
||||
const { pageType, storeType } = props;
|
||||
// store hooks
|
||||
const { getCurrentProjectFilteredPageIds } = useProjectPages();
|
||||
const { getCurrentProjectFilteredPageIds } = usePageStore(storeType);
|
||||
// derived values
|
||||
const filteredPageIds = getCurrentProjectFilteredPageIds(pageType);
|
||||
|
||||
|
|
@ -24,7 +25,7 @@ export const PagesListRoot: FC<TPagesListRoot> = observer((props) => {
|
|||
return (
|
||||
<ListLayout>
|
||||
{filteredPageIds.map((pageId) => (
|
||||
<PageListBlock key={pageId} pageId={pageId} usePage={useProjectPage} />
|
||||
<PageListBlock key={pageId} pageId={pageId} storeType={storeType} />
|
||||
))}
|
||||
</ListLayout>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -7,8 +7,10 @@ import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
|
|||
// components
|
||||
import { PageForm } from "@/components/pages";
|
||||
// hooks
|
||||
import { useProjectPages, useEventTracker } from "@/hooks/store";
|
||||
import { useEventTracker } from "@/hooks/store";
|
||||
import { useAppRouter } from "@/hooks/use-app-router";
|
||||
// plane web hooks
|
||||
import { EPageStoreType, usePageStore } from "@/plane-web/hooks/store";
|
||||
|
||||
type Props = {
|
||||
workspaceSlug: string;
|
||||
|
|
@ -17,10 +19,19 @@ type Props = {
|
|||
pageAccess?: EPageAccess;
|
||||
handleModalClose: () => void;
|
||||
redirectionEnabled?: boolean;
|
||||
storeType: EPageStoreType;
|
||||
};
|
||||
|
||||
export const CreatePageModal: FC<Props> = (props) => {
|
||||
const { workspaceSlug, projectId, isModalOpen, pageAccess, handleModalClose, redirectionEnabled = false } = props;
|
||||
const {
|
||||
workspaceSlug,
|
||||
projectId,
|
||||
isModalOpen,
|
||||
pageAccess,
|
||||
handleModalClose,
|
||||
redirectionEnabled = false,
|
||||
storeType,
|
||||
} = props;
|
||||
// states
|
||||
const [pageFormData, setPageFormData] = useState<Partial<TPage>>({
|
||||
id: undefined,
|
||||
|
|
@ -30,7 +41,7 @@ export const CreatePageModal: FC<Props> = (props) => {
|
|||
// router
|
||||
const router = useAppRouter();
|
||||
// store hooks
|
||||
const { createPage } = useProjectPages();
|
||||
const { createPage } = usePageStore(storeType);
|
||||
const { capturePageEvent } = useEventTracker();
|
||||
const handlePageFormData = <T extends keyof TPage>(key: T, value: TPage[T]) =>
|
||||
setPageFormData((prev) => ({ ...prev, [key]: value }));
|
||||
|
|
|
|||
|
|
@ -7,21 +7,25 @@ import { PAGE_DELETED } from "@plane/constants";
|
|||
import { AlertModalCore, TOAST_TYPE, setToast } from "@plane/ui";
|
||||
// constants
|
||||
// hooks
|
||||
import { useEventTracker, useProjectPages } from "@/hooks/store";
|
||||
import { useEventTracker } from "@/hooks/store";
|
||||
// plane web hooks
|
||||
import { EPageStoreType, usePageStore } from "@/plane-web/hooks/store";
|
||||
// store
|
||||
import { TPageInstance } from "@/store/pages/base-page";
|
||||
|
||||
type TConfirmPageDeletionProps = {
|
||||
page: TPageInstance;
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
page: TPageInstance;
|
||||
storeType: EPageStoreType;
|
||||
};
|
||||
|
||||
export const DeletePageModal: React.FC<TConfirmPageDeletionProps> = observer((props) => {
|
||||
const { page, isOpen, onClose } = props;
|
||||
const { isOpen, onClose, page, storeType } = props;
|
||||
// states
|
||||
const [isDeleting, setIsDeleting] = useState(false);
|
||||
// store hooks
|
||||
const { removePage } = useProjectPages();
|
||||
const { removePage } = usePageStore(storeType);
|
||||
const { capturePageEvent } = useEventTracker();
|
||||
if (!page || !page.id) return null;
|
||||
// derived values
|
||||
|
|
|
|||
|
|
@ -7,8 +7,10 @@ import { TPageNavigationTabs } from "@plane/types";
|
|||
// components
|
||||
import { DetailedEmptyState } from "@/components/empty-state";
|
||||
import { PageLoader } from "@/components/pages";
|
||||
import { useCommandPalette, useProjectPages, useUserPermissions } from "@/hooks/store";
|
||||
import { useCommandPalette, useUserPermissions } from "@/hooks/store";
|
||||
import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path";
|
||||
// plane web hooks
|
||||
import { EPageStoreType, usePageStore } from "@/plane-web/hooks/store";
|
||||
// assets
|
||||
import AllFiltersImage from "@/public/empty-state/pages/all-filters.svg";
|
||||
import NameFilterImage from "@/public/empty-state/pages/name-filter.svg";
|
||||
|
|
@ -16,15 +18,16 @@ import NameFilterImage from "@/public/empty-state/pages/name-filter.svg";
|
|||
type Props = {
|
||||
children: React.ReactNode;
|
||||
pageType: TPageNavigationTabs;
|
||||
storeType: EPageStoreType;
|
||||
};
|
||||
|
||||
export const PagesListMainContent: React.FC<Props> = observer((props) => {
|
||||
const { children, pageType } = props;
|
||||
const { children, pageType, storeType } = props;
|
||||
// plane hooks
|
||||
const { t } = useTranslation();
|
||||
// store hooks
|
||||
const { loader, isAnyPageAvailable, getCurrentProjectFilteredPageIds, getCurrentProjectPageIds, filters } =
|
||||
useProjectPages();
|
||||
usePageStore(storeType);
|
||||
const { toggleCreatePageModal } = useCommandPalette();
|
||||
const { allowPermissions } = useUserPermissions();
|
||||
// derived values
|
||||
|
|
|
|||
|
|
@ -3,24 +3,25 @@ import useSWR from "swr";
|
|||
import { TPageNavigationTabs } from "@plane/types";
|
||||
// components
|
||||
import { PagesListHeaderRoot, PagesListMainContent } from "@/components/pages";
|
||||
// hooks
|
||||
import { useProjectPages } from "@/hooks/store";
|
||||
// plane web hooks
|
||||
import { EPageStoreType, usePageStore } from "@/plane-web/hooks/store";
|
||||
|
||||
type TPageView = {
|
||||
workspaceSlug: string;
|
||||
projectId: string;
|
||||
pageType: TPageNavigationTabs;
|
||||
children: React.ReactNode;
|
||||
pageType: TPageNavigationTabs;
|
||||
projectId: string;
|
||||
storeType: EPageStoreType;
|
||||
workspaceSlug: string;
|
||||
};
|
||||
|
||||
export const PagesListView: React.FC<TPageView> = observer((props) => {
|
||||
const { workspaceSlug, projectId, pageType, children } = props;
|
||||
const { children, pageType, projectId, storeType, workspaceSlug } = props;
|
||||
// store hooks
|
||||
const { isAnyPageAvailable, getAllPages } = useProjectPages();
|
||||
const { isAnyPageAvailable, fetchPagesList } = usePageStore(storeType);
|
||||
// fetching pages list
|
||||
useSWR(
|
||||
workspaceSlug && projectId && pageType ? `PROJECT_PAGES_${projectId}` : null,
|
||||
workspaceSlug && projectId && pageType ? () => getAllPages(workspaceSlug, projectId, pageType) : null
|
||||
workspaceSlug && projectId && pageType ? () => fetchPagesList(workspaceSlug, projectId, pageType) : null
|
||||
);
|
||||
|
||||
// pages loader
|
||||
|
|
@ -28,9 +29,16 @@ export const PagesListView: React.FC<TPageView> = observer((props) => {
|
|||
<div className="relative w-full h-full overflow-hidden flex flex-col">
|
||||
{/* tab header */}
|
||||
{isAnyPageAvailable && (
|
||||
<PagesListHeaderRoot pageType={pageType} projectId={projectId} workspaceSlug={workspaceSlug} />
|
||||
<PagesListHeaderRoot
|
||||
pageType={pageType}
|
||||
projectId={projectId}
|
||||
storeType={storeType}
|
||||
workspaceSlug={workspaceSlug}
|
||||
/>
|
||||
)}
|
||||
<PagesListMainContent pageType={pageType}>{children}</PagesListMainContent>
|
||||
<PagesListMainContent pageType={pageType} storeType={storeType}>
|
||||
{children}
|
||||
</PagesListMainContent>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
export * from "./estimates";
|
||||
export * from "./notifications";
|
||||
export * from "./pages";
|
||||
export * from "./use-app-theme";
|
||||
export * from "./use-calendar-view";
|
||||
export * from "./use-command-palette";
|
||||
|
|
|
|||
|
|
@ -1,2 +0,0 @@
|
|||
export * from "./use-page";
|
||||
export * from "./use-project-page";
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
import { useContext } from "react";
|
||||
// mobx store
|
||||
import { StoreContext } from "@/lib/store-context";
|
||||
import { TUsePage } from "@/store/pages/base-page";
|
||||
// store
|
||||
import { TProjectPage } from "@/store/pages/project-page";
|
||||
|
||||
export const useProjectPage: TUsePage = (pageId: string | undefined): TProjectPage => {
|
||||
const context = useContext(StoreContext);
|
||||
if (context === undefined) throw new Error("usePage must be used within StoreProvider");
|
||||
|
||||
if (!pageId) return {} as TProjectPage;
|
||||
|
||||
return context.projectPages.data?.[pageId] ?? {};
|
||||
};
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
import { useContext } from "react";
|
||||
// context
|
||||
import { StoreContext } from "@/lib/store-context";
|
||||
// mobx store
|
||||
import { IProjectPageStore } from "@/store/pages/project-page.store";
|
||||
|
||||
export const useProjectPages = (): IProjectPageStore => {
|
||||
const context = useContext(StoreContext);
|
||||
if (context === undefined) throw new Error("useProjectPage must be used within StoreProvider");
|
||||
return context.projectPages;
|
||||
};
|
||||
|
|
@ -8,7 +8,9 @@ import {
|
|||
// helpers
|
||||
import { getPageName } from "@/helpers/page.helper";
|
||||
// hooks
|
||||
import { useProject, useProjectPage, useProjectView, useCycle, useModule } from "@/hooks/store";
|
||||
import { useProject, useProjectView, useCycle, useModule } from "@/hooks/store";
|
||||
// plane web hooks
|
||||
import { EPageStoreType, usePage } from "@/plane-web/hooks/store";
|
||||
|
||||
export const useFavoriteItemDetails = (workspaceSlug: string, favorite: IFavorite) => {
|
||||
const favoriteItemId = favorite?.entity_data?.id;
|
||||
|
|
@ -23,7 +25,10 @@ export const useFavoriteItemDetails = (workspaceSlug: string, favorite: IFavorit
|
|||
const { getModuleById } = useModule();
|
||||
|
||||
// derived values
|
||||
const pageDetail = useProjectPage(favoriteItemId ?? "");
|
||||
const pageDetail = usePage({
|
||||
pageId: favoriteItemId ?? "",
|
||||
storeType: EPageStoreType.PROJECT,
|
||||
});
|
||||
const viewDetails = getViewById(favoriteItemId ?? "");
|
||||
const cycleDetail = getCycleById(favoriteItemId ?? "");
|
||||
const moduleDetail = getModuleById(favoriteItemId ?? "");
|
||||
|
|
@ -40,7 +45,7 @@ export const useFavoriteItemDetails = (workspaceSlug: string, favorite: IFavorit
|
|||
itemIcon = getFavoriteItemIcon("project", currentProjectDetails?.logo_props || favoriteItemLogoProps);
|
||||
break;
|
||||
case "page":
|
||||
itemTitle = getPageName(pageDetail.name || favoriteItemName);
|
||||
itemTitle = getPageName(pageDetail?.name || favoriteItemName);
|
||||
itemIcon = getFavoriteItemIcon("page", pageDetail?.logo_props || favoriteItemLogoProps);
|
||||
break;
|
||||
case "view":
|
||||
|
|
|
|||
|
|
@ -64,8 +64,6 @@ export type TPageInstance = TBasePage &
|
|||
getRedirectionLink: () => string;
|
||||
};
|
||||
|
||||
export type TUsePage = (pageId: string | undefined) => TPageInstance;
|
||||
|
||||
export class BasePage implements TBasePage {
|
||||
// loaders
|
||||
isSubmitting: TNameDescriptionLoader = "saved";
|
||||
|
|
|
|||
|
|
@ -39,16 +39,16 @@ export interface IProjectPageStore {
|
|||
// helper actions
|
||||
getCurrentProjectPageIds: (pageType: TPageNavigationTabs) => string[] | undefined;
|
||||
getCurrentProjectFilteredPageIds: (pageType: TPageNavigationTabs) => string[] | undefined;
|
||||
pageById: (pageId: string) => TProjectPage | undefined;
|
||||
getPageById: (pageId: string) => TProjectPage | undefined;
|
||||
updateFilters: <T extends keyof TPageFilters>(filterKey: T, filterValue: TPageFilters[T]) => void;
|
||||
clearAllFilters: () => void;
|
||||
// actions
|
||||
getAllPages: (
|
||||
fetchPagesList: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
pageType: TPageNavigationTabs
|
||||
) => Promise<TPage[] | undefined>;
|
||||
getPageById: (workspaceSlug: string, projectId: string, pageId: string) => Promise<TPage | undefined>;
|
||||
fetchPageDetails: (workspaceSlug: string, projectId: string, pageId: string) => Promise<TPage | undefined>;
|
||||
createPage: (pageData: Partial<TPage>) => Promise<TPage | undefined>;
|
||||
removePage: (pageId: string) => Promise<void>;
|
||||
movePage: (workspaceSlug: string, projectId: string, pageId: string, newProjectId: string) => Promise<void>;
|
||||
|
|
@ -82,8 +82,8 @@ export class ProjectPageStore implements IProjectPageStore {
|
|||
updateFilters: action,
|
||||
clearAllFilters: action,
|
||||
// actions
|
||||
getAllPages: action,
|
||||
getPageById: action,
|
||||
fetchPagesList: action,
|
||||
fetchPageDetails: action,
|
||||
createPage: action,
|
||||
removePage: action,
|
||||
movePage: action,
|
||||
|
|
@ -164,7 +164,7 @@ export class ProjectPageStore implements IProjectPageStore {
|
|||
* @description get the page store by id
|
||||
* @param {string} pageId
|
||||
*/
|
||||
pageById = computedFn((pageId: string) => this.data?.[pageId] || undefined);
|
||||
getPageById = computedFn((pageId: string) => this.data?.[pageId] || undefined);
|
||||
|
||||
updateFilters = <T extends keyof TPageFilters>(filterKey: T, filterValue: TPageFilters[T]) => {
|
||||
runInAction(() => {
|
||||
|
|
@ -183,7 +183,7 @@ export class ProjectPageStore implements IProjectPageStore {
|
|||
/**
|
||||
* @description fetch all the pages
|
||||
*/
|
||||
getAllPages = async (workspaceSlug: string, projectId: string, pageType: TPageNavigationTabs) => {
|
||||
fetchPagesList = async (workspaceSlug: string, projectId: string, pageType: TPageNavigationTabs) => {
|
||||
try {
|
||||
if (!workspaceSlug || !projectId) return undefined;
|
||||
|
||||
|
|
@ -216,11 +216,11 @@ export class ProjectPageStore implements IProjectPageStore {
|
|||
* @description fetch the details of a page
|
||||
* @param {string} pageId
|
||||
*/
|
||||
getPageById = async (workspaceSlug: string, projectId: string, pageId: string) => {
|
||||
fetchPageDetails = async (workspaceSlug: string, projectId: string, pageId: string) => {
|
||||
try {
|
||||
if (!workspaceSlug || !projectId || !pageId) return undefined;
|
||||
|
||||
const currentPageId = this.pageById(pageId);
|
||||
const currentPageId = this.getPageById(pageId);
|
||||
runInAction(() => {
|
||||
this.loader = currentPageId ? `mutation-loader` : `init-loader`;
|
||||
this.error = undefined;
|
||||
|
|
|
|||
1
web/ee/hooks/store/index.ts
Normal file
1
web/ee/hooks/store/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from "ce/hooks/store";
|
||||
Loading…
Add table
Add a link
Reference in a new issue