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

+ 0 - 1
.serena/memories/page-transition-and-rendering-flow.md

@@ -58,7 +58,6 @@
     - **APIエラー時 (例: 404 Not Found)**:
         - `pageErrorAtom` にエラーオブジェクトを設定します。
         - `pageNotFoundAtom` を `true` に設定します。
-        - パスがユーザー作成可能でない場合 (`/user` など) は `pageNotCreatableAtom` も `true` に設定します。
         - 最後に `pageLoadingAtom` を `false` に設定します。
 5.  **`PageView` の最終レンダリング**:
     - `currentPageDataAtom` の更新がトリガーとなり、`PageView` コンポーネントが新しいデータで再レンダリングされます。

+ 22 - 12
apps/app/src/states/page/hooks.ts

@@ -1,4 +1,7 @@
-import { pagePathUtils } from '@growi/core/dist/utils';
+import {
+  isCreatablePage,
+  isPermalink,
+} from '@growi/core/dist/utils/page-path-utils';
 import { useAtomValue } from 'jotai';
 import { useAtomCallback } from 'jotai/utils';
 import { useCallback, useMemo } from 'react';
@@ -10,11 +13,9 @@ import {
   currentPagePathAtom,
   isForbiddenAtom,
   isIdenticalPathAtom,
-  isNotCreatableAtom,
   isRevisionOutdatedAtom,
   isTrashPageAtom,
   latestRevisionAtom,
-  pageNotCreatableAtom,
   pageNotFoundAtom,
   redirectFromAtom,
   remoteRevisionBodyAtom,
@@ -38,14 +39,10 @@ export const useCurrentPageData = () => useAtomValue(currentPageDataAtom);
 
 export const usePageNotFound = () => useAtomValue(pageNotFoundAtom);
 
-export const usePageNotCreatable = () => useAtomValue(pageNotCreatableAtom);
-
 export const useIsIdenticalPath = () => useAtomValue(isIdenticalPathAtom);
 
 export const useIsForbidden = () => useAtomValue(isForbiddenAtom);
 
-export const useIsNotCreatable = () => useAtomValue(isNotCreatableAtom);
-
 export const useLatestRevision = () => useAtomValue(latestRevisionAtom);
 
 export const useShareLinkId = () => useAtomValue(shareLinkIdAtom);
@@ -80,7 +77,7 @@ export const useCurrentPagePath = (): string | undefined => {
   if (currentPagePath != null) {
     return currentPagePath;
   }
-  if (currentPathname != null && !pagePathUtils.isPermalink(currentPathname)) {
+  if (currentPathname != null && !isPermalink(currentPathname)) {
     return currentPathname;
   }
   return undefined;
@@ -99,24 +96,37 @@ export const useIsTrashPage = (): boolean => useAtomValue(isTrashPageAtom);
 export const useIsRevisionOutdated = (): boolean =>
   useAtomValue(isRevisionOutdatedAtom);
 
+/**
+ * Computed hook for checking if current page is creatable
+ */
+export const useIsNotCreatable = (): boolean => {
+  const pagePath = useCurrentPagePath();
+  return pagePath == null ? true : !isCreatablePage(pagePath);
+};
+
 /**
  * Computed hook for checking if current page is editable
  */
 export const useIsEditable = () => {
   const isGuestUser = useIsGuestUser();
   const isReadOnlyUser = useIsReadOnlyUser();
+  const isNotCreatable = useIsNotCreatable();
 
   const getCombinedConditions = useAtomCallback(
     useCallback((get) => {
       const isForbidden = get(isForbiddenAtom);
-      const isNotCreatable = get(isNotCreatableAtom);
       const isIdenticalPath = get(isIdenticalPathAtom);
 
-      return !isForbidden && !isIdenticalPath && !isNotCreatable;
+      return !isForbidden && !isIdenticalPath;
     }, []),
   );
 
   return useMemo(() => {
-    return !isGuestUser && !isReadOnlyUser && getCombinedConditions();
-  }, [getCombinedConditions, isGuestUser, isReadOnlyUser]);
+    return (
+      !isGuestUser &&
+      !isReadOnlyUser &&
+      !isNotCreatable &&
+      getCombinedConditions()
+    );
+  }, [getCombinedConditions, isGuestUser, isReadOnlyUser, isNotCreatable]);
 };

+ 0 - 2
apps/app/src/states/page/internal-atoms.ts

@@ -11,10 +11,8 @@ import { atom } from 'jotai';
 export const currentPageIdAtom = atom<string>();
 export const currentPageDataAtom = atom<IPagePopulatedToShowRevision>();
 export const pageNotFoundAtom = atom(false);
-export const pageNotCreatableAtom = atom(false);
 export const isIdenticalPathAtom = atom<boolean>(false);
 export const isForbiddenAtom = atom<boolean>(false);
-export const isNotCreatableAtom = atom<boolean>(false);
 export const latestRevisionAtom = atom(true);
 
 // ShareLink page state atoms (internal)

+ 1 - 3
apps/app/src/states/page/use-fetch-current-page.spec.tsx

@@ -23,7 +23,6 @@ import {
   currentPageIdAtom,
   pageErrorAtom,
   pageLoadingAtom,
-  pageNotCreatableAtom,
   pageNotFoundAtom,
 } from '~/states/page/internal-atoms';
 
@@ -286,7 +285,7 @@ describe('useFetchCurrentPage - Integration Test', () => {
     });
   });
 
-  it('should set pageNotFoundAtom and pageNotCreatableAtom on 404 error for a non-creatable path', async () => {
+  it('should set pageNotFoundAtom on 404 error for a non-creatable path', async () => {
     // Arrange
     const notCreatablePath = '/user';
     const apiError = {
@@ -303,7 +302,6 @@ describe('useFetchCurrentPage - Integration Test', () => {
     // Assert
     await waitFor(() => {
       expect(store.get(pageNotFoundAtom)).toBe(true);
-      expect(store.get(pageNotCreatableAtom)).toBe(true);
       expect(store.get(pageErrorAtom)).toEqual(apiError);
     });
   });

+ 0 - 5
apps/app/src/states/page/use-fetch-current-page.ts

@@ -16,7 +16,6 @@ import {
   currentPageIdAtom,
   pageErrorAtom,
   pageLoadingAtom,
-  pageNotCreatableAtom,
   pageNotFoundAtom,
   shareLinkIdAtom,
 } from './internal-atoms';
@@ -137,7 +136,6 @@ export const useFetchCurrentPage = (): {
           set(currentPageDataAtom, newData);
           set(currentPageIdAtom, newData._id);
           set(pageNotFoundAtom, false);
-          set(pageNotCreatableAtom, false);
 
           return newData;
         } catch (err) {
@@ -146,9 +144,6 @@ export const useFetchCurrentPage = (): {
           const apiError = err as any; // eslint-disable-line @typescript-eslint/no-explicit-any
           if (apiError.response?.status === 404) {
             set(pageNotFoundAtom, true);
-            if (params.path != null) {
-              set(pageNotCreatableAtom, !isCreatablePage(params.path));
-            }
           }
         } finally {
           set(pageLoadingAtom, false);