Просмотр исходного кода

migrate useSelectedGrant and usePageControlsX

Yuki Takei 7 месяцев назад
Родитель
Сommit
61c998c9de

+ 5 - 6
apps/app/src/client/components/PageControls/PageControls.tsx

@@ -25,10 +25,9 @@ import { isUsersHomepageDeletionEnabledAtom } from '~/states/server-configuratio
 import {
   EditorMode, useEditorMode,
 } from '~/states/ui/editor';
+import { useSetPageControlsX } from '~/states/ui/page';
 import { useTagEditModal, type IPageForPageDuplicateModal } from '~/stores/modal';
-import {
-  useIsDeviceLargerThanMd, usePageControlsX,
-} from '~/stores/ui';
+import { useIsDeviceLargerThanMd } from '~/stores/ui';
 import loggerFactory from '~/utils/logger';
 
 import { useSWRxPageInfo, useSWRxTagsInfo } from '../../../stores/page';
@@ -148,7 +147,7 @@ const PageControlsSubstance = (props: PageControlsSubstanceProps): JSX.Element =
   const likerIds = isIPageInfoForEntity(pageInfo) ? (pageInfo.likerIds ?? []).slice(0, 15) : [];
   const seenUserIds = isIPageInfoForEntity(pageInfo) ? (pageInfo.seenUserIds ?? []).slice(0, 15) : [];
 
-  const { mutate: mutatePageControlsX } = usePageControlsX();
+  const setPageControlsX = useSetPageControlsX();
 
   const pageControlsRef = useRef<HTMLDivElement>(null);
   const [pageControlsRect] = useRect(pageControlsRef);
@@ -157,8 +156,8 @@ const PageControlsSubstance = (props: PageControlsSubstanceProps): JSX.Element =
     if (pageControlsRect?.x == null) {
       return;
     }
-    mutatePageControlsX(pageControlsRect.x);
-  }, [pageControlsRect?.x, mutatePageControlsX]);
+    setPageControlsX(pageControlsRect.x);
+  }, [pageControlsRect?.x, setPageControlsX]);
 
 
   // Put in a mixture of seenUserIds and likerIds data to make the cache work

+ 8 - 8
apps/app/src/client/components/PageEditor/EditorNavbarBottom/GrantSelector.tsx

@@ -18,8 +18,8 @@ import type { UserRelatedGroupsData } from '~/interfaces/page';
 import { UserGroupPageGrantStatus } from '~/interfaces/page';
 import { useCurrentUser } from '~/states/global';
 import { useCurrentPageId } from '~/states/page';
+import { useSelectedGrant } from '~/states/ui/editor';
 import { useSWRxCurrentGrantData } from '~/stores/page';
-import { useSelectedGrant } from '~/stores/ui';
 
 
 const AVAILABLE_GRANTS = [
@@ -65,7 +65,7 @@ export const GrantSelector = (props: Props): JSX.Element => {
   const currentUser = useCurrentUser();
 
   const shouldFetch = isSelectGroupModalShown;
-  const { data: selectedGrant, mutate: mutateSelectedGrant } = useSelectedGrant();
+  const [selectedGrant, setSelectedGrant] = useSelectedGrant();
   const currentPageId = useCurrentPageId();
   const { data: grantData } = useSWRxCurrentGrantData(currentPageId);
 
@@ -80,11 +80,11 @@ export const GrantSelector = (props: Props): JSX.Element => {
       ?.userRelatedGroups.filter(group => group.status === UserGroupPageGrantStatus.isGranted)?.map((group) => {
         return { item: group.id, type: group.type };
       }) ?? [];
-    mutateSelectedGrant({
+    setSelectedGrant({
       grant: currentPageGrant.grant,
       userRelatedGrantedGroups,
     });
-  }, [grantData?.grantData.currentPageGrant, mutateSelectedGrant]);
+  }, [grantData?.grantData.currentPageGrant, setSelectedGrant]);
 
   // sync grant data
   useEffect(() => {
@@ -106,8 +106,8 @@ export const GrantSelector = (props: Props): JSX.Element => {
       return;
     }
 
-    mutateSelectedGrant({ grant, userRelatedGrantedGroups: undefined });
-  }, [mutateSelectedGrant, showSelectGroupModal, applyCurrentPageGrantToSelectedGrant, selectedGrant?.grant]);
+    setSelectedGrant({ grant, userRelatedGrantedGroups: undefined });
+  }, [setSelectedGrant, showSelectGroupModal, applyCurrentPageGrantToSelectedGrant, selectedGrant?.grant]);
 
   const groupListItemClickHandler = useCallback((clickedGroup: UserRelatedGroupsData) => {
     const userRelatedGrantedGroups = selectedGrant?.userRelatedGrantedGroups ?? [];
@@ -120,8 +120,8 @@ export const GrantSelector = (props: Props): JSX.Element => {
     else {
       userRelatedGrantedGroupsCopy = userRelatedGrantedGroupsCopy.filter(group => getIdForRef(group.item) !== clickedGroup.id);
     }
-    mutateSelectedGrant({ grant: 5, userRelatedGrantedGroups: userRelatedGrantedGroupsCopy });
-  }, [mutateSelectedGrant, selectedGrant?.userRelatedGrantedGroups]);
+    setSelectedGrant({ grant: 5, userRelatedGrantedGroups: userRelatedGrantedGroupsCopy });
+  }, [setSelectedGrant, selectedGrant?.userRelatedGrantedGroups]);
 
   /**
    * Render grant selector DOM.

+ 3 - 3
apps/app/src/client/components/PageEditor/EditorNavbarBottom/SavePageControls.tsx

@@ -20,9 +20,9 @@ import {
   isAclEnabledAtom,
   isSlackConfiguredAtom,
 } from '~/states/server-configurations';
-import { useEditorMode } from '~/states/ui/editor';
+import { useEditorMode, useSelectedGrant } from '~/states/ui/editor';
 import { useWaitingSaveProcessing, useSWRxSlackChannels, useIsSlackEnabled } from '~/stores/editor';
-import { useIsDeviceLargerThanMd, useSelectedGrant } from '~/stores/ui';
+import { useIsDeviceLargerThanMd } from '~/stores/ui';
 import loggerFactory from '~/utils/logger';
 
 import { NotAvailable } from '../../NotAvailable';
@@ -45,7 +45,7 @@ const SavePageButton = (props: {slackChannels: string, isSlackEnabled?: boolean,
   const { t } = useTranslation();
   const { data: _isWaitingSaveProcessing } = useWaitingSaveProcessing();
   const [isSavePageModalShown, setIsSavePageModalShown] = useState<boolean>(false);
-  const { data: selectedGrant } = useSelectedGrant();
+  const [selectedGrant] = useSelectedGrant();
 
   const { slackChannels, isSlackEnabled, isDeviceLargerThanMd } = props;
 

+ 5 - 3
apps/app/src/client/components/PageEditor/PageEditor.tsx

@@ -38,7 +38,9 @@ import {
   isEnabledAttachTitleHeaderAtom,
   isIndentSizeForcedAtom,
 } from '~/states/server-configurations';
-import { useEditorMode, EditorMode, useEditingMarkdown } from '~/states/ui/editor';
+import {
+  useEditorMode, EditorMode, useEditingMarkdown, useSelectedGrant,
+} from '~/states/ui/editor';
 import {
   useAcceptedUploadFileType, useIsEnableUnifiedMergeView,
 } from '~/stores-universal/context';
@@ -54,7 +56,7 @@ import {
 } from '~/stores/page';
 import { mutatePageTree, mutateRecentlyUpdated } from '~/stores/page-listing';
 import { usePreviewOptions } from '~/stores/renderer';
-import { useIsUntitledPage, useSelectedGrant } from '~/stores/ui';
+import { useIsUntitledPage } from '~/stores/ui';
 import { useEditingClients } from '~/stores/use-editing-clients';
 import loggerFactory from '~/utils/logger';
 
@@ -103,7 +105,7 @@ export const PageEditorSubstance = (props: Props): JSX.Element => {
   const currentPagePath = useCurrentPagePath();
   const currentPathname = useCurrentPathname();
   const currentPage = useCurrentPageData();
-  const { data: selectedGrant } = useSelectedGrant();
+  const [selectedGrant] = useSelectedGrant();
   const [editingMarkdown] = useEditingMarkdown();
   const isEnabledAttachTitleHeader = useAtomValue(isEnabledAttachTitleHeaderAtom);
   const templateBody = useTemplateBody();

+ 2 - 2
apps/app/src/client/components/PageHeader/PageHeader.tsx

@@ -3,7 +3,7 @@ import {
 } from 'react';
 
 import { useCurrentPageData } from '~/states/page';
-import { usePageControlsX } from '~/stores/ui';
+import { usePageControlsX } from '~/states/ui/page';
 
 import { PagePathHeader } from './PagePathHeader';
 import { PageTitleHeader } from './PageTitleHeader';
@@ -15,7 +15,7 @@ const moduleClass = styles['page-header'] ?? '';
 export const PageHeader = (): JSX.Element => {
 
   const currentPage = useCurrentPageData();
-  const { data: pageControlsX } = usePageControlsX();
+  const pageControlsX = usePageControlsX();
   const pageHeaderRef = useRef<HTMLDivElement>(null);
 
   const [maxWidth, setMaxWidth] = useState<number>();

+ 2 - 4
apps/app/src/client/components/PagePathNavSticky/PagePathNavSticky.tsx

@@ -7,10 +7,8 @@ import { pagePathUtils } from '@growi/core/dist/utils';
 import Sticky from 'react-stickynode';
 
 import LinkedPagePath from '~/models/linked-page-path';
+import { usePageControlsX } from '~/states/ui/page';
 import { useSidebarMode, useCurrentProductNavWidth } from '~/states/ui/sidebar';
-import {
-  usePageControlsX,
-} from '~/stores/ui';
 
 import { PagePathHierarchicalLink } from '../../../components/Common/PagePathHierarchicalLink';
 import type { PagePathNavLayoutProps } from '../../../components/Common/PagePathNav';
@@ -28,7 +26,7 @@ const { isTrashPage } = pagePathUtils;
 export const PagePathNavSticky = (props: PagePathNavLayoutProps): JSX.Element => {
   const { pagePath } = props;
 
-  const { data: pageControlsX } = usePageControlsX();
+  const pageControlsX = usePageControlsX();
   const [sidebarWidth] = useCurrentProductNavWidth();
   const { sidebarMode } = useSidebarMode();
   const pagePathNavRef = useRef<HTMLDivElement>(null);

+ 11 - 0
apps/app/src/states/ui/editor/atoms.ts

@@ -1,6 +1,9 @@
+import { PageGrant } from '@growi/core/dist/interfaces';
 import { isServer } from '@growi/core/dist/utils';
 import { atom } from 'jotai';
 
+import type { IPageSelectedGrant } from '~/interfaces/page';
+
 import { EditorMode, EditorModeHash } from './types';
 import { determineEditorModeByHash } from './utils';
 
@@ -39,3 +42,11 @@ export const editorModeAtom = atom(
  * Atom for editing markdown content
  */
 export const editingMarkdownAtom = atom<string>('');
+
+/**
+ * Atom for selected grant in page editor
+ * Stores temporary grant selection before it's applied to the page
+ */
+export const selectedGrantAtom = atom<IPageSelectedGrant | null>({
+  grant: PageGrant.GRANT_PUBLIC,
+});

+ 7 - 1
apps/app/src/states/ui/editor/hooks.ts

@@ -4,7 +4,7 @@ import { useCallback } from 'react';
 import { useIsEditable } from '~/states/context';
 import { usePageNotFound } from '~/states/page';
 
-import { editingMarkdownAtom, editorModeAtom } from './atoms';
+import { editingMarkdownAtom, editorModeAtom, selectedGrantAtom } from './atoms';
 import { EditorMode, type UseEditorModeReturn } from './types';
 
 export const useEditorMode = (): UseEditorModeReturn => {
@@ -47,3 +47,9 @@ export const useEditorMode = (): UseEditorModeReturn => {
 };
 
 export const useEditingMarkdown = () => useAtom(editingMarkdownAtom);
+
+/**
+ * Hook for managing selected grant in page editor
+ * Used for temporary grant selection before applying to the page
+ */
+export const useSelectedGrant = () => useAtom(selectedGrantAtom);

+ 2 - 2
apps/app/src/states/ui/editor/index.ts

@@ -1,7 +1,7 @@
 // Export only the essential public API
 
-export { editingMarkdownAtom } from './atoms';
-export { useEditingMarkdown, useEditorMode } from './hooks';
+export { editingMarkdownAtom, selectedGrantAtom } from './atoms';
+export { useEditingMarkdown, useEditorMode, useSelectedGrant } from './hooks';
 export type { EditorMode as EditorModeType } from './types';
 export { EditorMode } from './types';
 

+ 17 - 0
apps/app/src/states/ui/page.ts

@@ -0,0 +1,17 @@
+import { atom, useAtomValue, useSetAtom } from 'jotai';
+
+// Page Controls X coordinate atom
+// Stores the x coordinate of the PageControls component for layout calculations
+const pageControlsXAtom = atom<number | undefined>(undefined);
+
+/**
+ * Hook to get the x coordinate of PageControls component
+ * Used for layout calculations in PageHeader and PagePathNavSticky
+ */
+export const usePageControlsX = () => useAtomValue(pageControlsXAtom);
+
+/**
+ * Hook to set the x coordinate of PageControls component
+ * Used specifically in PageControls component to update the position
+ */
+export const useSetPageControlsX = () => useSetAtom(pageControlsXAtom);

+ 0 - 11
apps/app/src/stores/ui.tsx

@@ -3,7 +3,6 @@ import {
   useLayoutEffect,
 } from 'react';
 
-import { PageGrant, type Nullable } from '@growi/core';
 import { useSWRStatic } from '@growi/core/dist/swr';
 import { pagePathUtils, isClient } from '@growi/core/dist/utils';
 import { Breakpoint } from '@growi/ui/dist/interfaces';
@@ -15,7 +14,6 @@ import {
 } from 'swr';
 import useSWRImmutable from 'swr/immutable';
 
-import type { IPageSelectedGrant } from '~/interfaces/page';
 import type { UpdateDescCountData } from '~/interfaces/websocket';
 import {
   useIsEditable, useIsIdenticalPath, useIsReadOnlyUser, useIsSharedUser,
@@ -145,15 +143,6 @@ export const useIsDeviceLargerThanLg = (): SWRResponse<boolean, Error> => {
   return useSWRStatic(key);
 };
 
-
-export const usePageControlsX = (initialData?: number): SWRResponse<number> => {
-  return useSWRStatic('pageControlsX', initialData);
-};
-
-export const useSelectedGrant = (initialData?: Nullable<IPageSelectedGrant>): SWRResponse<Nullable<IPageSelectedGrant>, Error> => {
-  return useSWRStatic<Nullable<IPageSelectedGrant>, Error>('selectedGrant', initialData, { fallbackData: { grant: PageGrant.GRANT_PUBLIC } });
-};
-
 type PageTreeDescCountMapUtils = {
   update(newData?: UpdateDescCountData): Promise<UpdateDescCountData | undefined>
   getDescCount(pageId?: string): number | null | undefined