diff --git a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(detail)/[pageId]/page.tsx b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(detail)/[pageId]/page.tsx index 4a87a9cbc4b..2e45b9ba394 100644 --- a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(detail)/[pageId]/page.tsx +++ b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(detail)/[pageId]/page.tsx @@ -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(() => { ); + if (!page) return null; + return ( <> @@ -154,6 +161,7 @@ const PageDetailsPage = observer(() => { config={pageRootConfig} handlers={pageRootHandlers} page={page} + storeType={EPageStoreType.PROJECT} webhookConnectionParams={webhookConnectionParams} workspaceSlug={workspaceSlug?.toString() ?? ""} /> diff --git a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(detail)/header.tsx b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(detail)/header.tsx index 3ca5ba4b8cf..f8292f44261 100644 --- a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(detail)/header.tsx +++ b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(detail)/header.tsx @@ -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(); diff --git a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(list)/header.tsx b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(list)/header.tsx index 0173148df19..ca15df8f5f1 100644 --- a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(list)/header.tsx +++ b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(list)/header.tsx @@ -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 () => { diff --git a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(list)/page.tsx b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(list)/page.tsx index 547584f51a1..56d89d7f452 100644 --- a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(list)/page.tsx +++ b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(list)/page.tsx @@ -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(() => { <> - + ); diff --git a/web/ce/components/command-palette/modals/project-level.tsx b/web/ce/components/command-palette/modals/project-level.tsx index 324af8d4834..e0ff03a48b0 100644 --- a/web/ce/components/command-palette/modals/project-level.tsx +++ b/web/ce/components/command-palette/modals/project-level.tsx @@ -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} /> ); diff --git a/web/ce/hooks/store/index.ts b/web/ce/hooks/store/index.ts new file mode 100644 index 00000000000..1962c9b2627 --- /dev/null +++ b/web/ce/hooks/store/index.ts @@ -0,0 +1,2 @@ +export * from "./use-page-store"; +export * from "./use-page"; diff --git a/web/ce/hooks/store/use-page-store.ts b/web/ce/hooks/store/use-page-store.ts new file mode 100644 index 00000000000..91bf9306be1 --- /dev/null +++ b/web/ce/hooks/store/use-page-store.ts @@ -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 = (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}`); +}; diff --git a/web/ce/hooks/store/use-page.ts b/web/ce/hooks/store/use-page.ts new file mode 100644 index 00000000000..c7bd7ceede0 --- /dev/null +++ b/web/ce/hooks/store/use-page.ts @@ -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); +}; diff --git a/web/core/components/pages/dropdowns/actions.tsx b/web/core/components/pages/dropdowns/actions.tsx index 2992578c2b8..b0371345512 100644 --- a/web/core/components/pages/dropdowns/actions.tsx +++ b/web/core/components/pages/dropdowns/actions.tsx @@ -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; + storeType: EPageStoreType; }; export const PageActions: React.FC = 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 = observer((props) => { return ( <> setMovePageModal(false)} page={page} /> - setDeletePageModal(false)} page={page} /> + setDeletePageModal(false)} + page={page} + storeType={storeType} + /> {parentRef && } {arrangedOptions.map((item) => { diff --git a/web/core/components/pages/editor/header/extra-options.tsx b/web/core/components/pages/editor/header/extra-options.tsx index 2bc22b1281a..dfcfee53ca4 100644 --- a/web/core/components/pages/editor/header/extra-options.tsx +++ b/web/core/components/pages/editor/header/extra-options.tsx @@ -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 = 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 = observer((props) => { /> )} - + ); }); diff --git a/web/core/components/pages/editor/header/mobile-root.tsx b/web/core/components/pages/editor/header/mobile-root.tsx index 6f8be2977d8..22f25e2541f 100644 --- a/web/core/components/pages/editor/header/mobile-root.tsx +++ b/web/core/components/pages/editor/header/mobile-root.tsx @@ -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 = 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 = observer((props) => { setSidePeekVisible={setSidePeekVisible} /> - +
{isContentEditable && editorRef && } diff --git a/web/core/components/pages/editor/header/options-dropdown.tsx b/web/core/components/pages/editor/header/options-dropdown.tsx index e1807bcc9c6..38f0a4e239e 100644 --- a/web/core/components/pages/editor/header/options-dropdown.tsx +++ b/web/core/components/pages/editor/header/options-dropdown.tsx @@ -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 = 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 = observer((props) => { "export", ]} page={page} + storeType={storeType} /> ); diff --git a/web/core/components/pages/editor/header/root.tsx b/web/core/components/pages/editor/header/root.tsx index a9dfdad51b3..552ba60097c 100644 --- a/web/core/components/pages/editor/header/root.tsx +++ b/web/core/components/pages/editor/header/root.tsx @@ -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 = 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 = observer((props) => { )} - +
= observer((props) => { page={page} sidePeekVisible={sidePeekVisible} setSidePeekVisible={setSidePeekVisible} + storeType={storeType} />
diff --git a/web/core/components/pages/editor/page-root.tsx b/web/core/components/pages/editor/page-root.tsx index bc9c497806f..c80a52d4349 100644 --- a/web/core/components/pages/editor/page-root.tsx +++ b/web/core/components/pages/editor/page-root.tsx @@ -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} /> = 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(); diff --git a/web/core/components/pages/list/block-item-action.tsx b/web/core/components/pages/list/block-item-action.tsx index 191a22ab3b3..58e3a8e2a0f 100644 --- a/web/core/components/pages/list/block-item-action.tsx +++ b/web/core/components/pages/list/block-item-action.tsx @@ -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; + storeType: EPageStoreType; }; export const BlockItemAction: FC = 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 = observer((props) => { ]} page={page} parentRef={parentRef} + storeType={storeType} /> ); diff --git a/web/core/components/pages/list/block.tsx b/web/core/components/pages/list/block.tsx index 21e65f6bc73..cd3ddbdae41 100644 --- a/web/core/components/pages/list/block.tsx +++ b/web/core/components/pages/list/block.tsx @@ -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 = 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 = observer((props) => { } title={getPageName(name)} itemLink={getRedirectionLink()} - actionableItems={} + actionableItems={} isMobile={isMobile} parentRef={parentRef} /> diff --git a/web/core/components/pages/list/root.tsx b/web/core/components/pages/list/root.tsx index 75109d1e2b3..db8196b29c3 100644 --- a/web/core/components/pages/list/root.tsx +++ b/web/core/components/pages/list/root.tsx @@ -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 = 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 = observer((props) => { return ( {filteredPageIds.map((pageId) => ( - + ))} ); diff --git a/web/core/components/pages/modals/create-page-modal.tsx b/web/core/components/pages/modals/create-page-modal.tsx index baef54f025f..4be65bda026 100644 --- a/web/core/components/pages/modals/create-page-modal.tsx +++ b/web/core/components/pages/modals/create-page-modal.tsx @@ -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) => { - const { workspaceSlug, projectId, isModalOpen, pageAccess, handleModalClose, redirectionEnabled = false } = props; + const { + workspaceSlug, + projectId, + isModalOpen, + pageAccess, + handleModalClose, + redirectionEnabled = false, + storeType, + } = props; // states const [pageFormData, setPageFormData] = useState>({ id: undefined, @@ -30,7 +41,7 @@ export const CreatePageModal: FC = (props) => { // router const router = useAppRouter(); // store hooks - const { createPage } = useProjectPages(); + const { createPage } = usePageStore(storeType); const { capturePageEvent } = useEventTracker(); const handlePageFormData = (key: T, value: TPage[T]) => setPageFormData((prev) => ({ ...prev, [key]: value })); diff --git a/web/core/components/pages/modals/delete-page-modal.tsx b/web/core/components/pages/modals/delete-page-modal.tsx index 79d9213b9d8..caeac392654 100644 --- a/web/core/components/pages/modals/delete-page-modal.tsx +++ b/web/core/components/pages/modals/delete-page-modal.tsx @@ -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 = 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 diff --git a/web/core/components/pages/pages-list-main-content.tsx b/web/core/components/pages/pages-list-main-content.tsx index 4c5aa0907cc..83435a9689c 100644 --- a/web/core/components/pages/pages-list-main-content.tsx +++ b/web/core/components/pages/pages-list-main-content.tsx @@ -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 = 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 diff --git a/web/core/components/pages/pages-list-view.tsx b/web/core/components/pages/pages-list-view.tsx index 7b106a458c2..eccaf5e9bcd 100644 --- a/web/core/components/pages/pages-list-view.tsx +++ b/web/core/components/pages/pages-list-view.tsx @@ -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 = 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 = observer((props) => {
{/* tab header */} {isAnyPageAvailable && ( - + )} - {children} + + {children} +
); }); diff --git a/web/core/hooks/store/index.ts b/web/core/hooks/store/index.ts index fa9ff44cc9b..7f2d3b89d88 100644 --- a/web/core/hooks/store/index.ts +++ b/web/core/hooks/store/index.ts @@ -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"; diff --git a/web/core/hooks/store/pages/index.ts b/web/core/hooks/store/pages/index.ts deleted file mode 100644 index 06f4ab447d9..00000000000 --- a/web/core/hooks/store/pages/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./use-page"; -export * from "./use-project-page"; diff --git a/web/core/hooks/store/pages/use-page.ts b/web/core/hooks/store/pages/use-page.ts deleted file mode 100644 index 59f974a3ce0..00000000000 --- a/web/core/hooks/store/pages/use-page.ts +++ /dev/null @@ -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] ?? {}; -}; diff --git a/web/core/hooks/store/pages/use-project-page.ts b/web/core/hooks/store/pages/use-project-page.ts deleted file mode 100644 index c6fb088d144..00000000000 --- a/web/core/hooks/store/pages/use-project-page.ts +++ /dev/null @@ -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; -}; diff --git a/web/core/hooks/use-favorite-item-details.tsx b/web/core/hooks/use-favorite-item-details.tsx index e23228ea76d..114438b0431 100644 --- a/web/core/hooks/use-favorite-item-details.tsx +++ b/web/core/hooks/use-favorite-item-details.tsx @@ -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": diff --git a/web/core/store/pages/base-page.ts b/web/core/store/pages/base-page.ts index e645d0f343b..8b828a5591c 100644 --- a/web/core/store/pages/base-page.ts +++ b/web/core/store/pages/base-page.ts @@ -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"; diff --git a/web/core/store/pages/project-page.store.ts b/web/core/store/pages/project-page.store.ts index ea4d96a102a..d5773b12629 100644 --- a/web/core/store/pages/project-page.store.ts +++ b/web/core/store/pages/project-page.store.ts @@ -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: (filterKey: T, filterValue: TPageFilters[T]) => void; clearAllFilters: () => void; // actions - getAllPages: ( + fetchPagesList: ( workspaceSlug: string, projectId: string, pageType: TPageNavigationTabs ) => Promise; - getPageById: (workspaceSlug: string, projectId: string, pageId: string) => Promise; + fetchPageDetails: (workspaceSlug: string, projectId: string, pageId: string) => Promise; createPage: (pageData: Partial) => Promise; removePage: (pageId: string) => Promise; movePage: (workspaceSlug: string, projectId: string, pageId: string, newProjectId: string) => Promise; @@ -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 = (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; diff --git a/web/ee/hooks/store/index.ts b/web/ee/hooks/store/index.ts new file mode 100644 index 00000000000..6ce80b4fb5a --- /dev/null +++ b/web/ee/hooks/store/index.ts @@ -0,0 +1 @@ +export * from "ce/hooks/store";