BookmarkFolderTree.tsx 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. import React, { useCallback } from 'react';
  2. import type { IPageToDeleteWithMeta } from '@growi/core';
  3. import { useTranslation } from 'next-i18next';
  4. import { useRouter } from 'next/router';
  5. import { DndProvider } from 'react-dnd';
  6. import { HTML5Backend } from 'react-dnd-html5-backend';
  7. import { toastSuccess } from '~/client/util/toastr';
  8. import type { OnDeletedFunction } from '~/interfaces/ui';
  9. import { useIsReadOnlyUser } from '~/states/context';
  10. import { useCurrentPageData } from '~/states/page';
  11. import { usePageDeleteModalActions } from '~/states/ui/modal/page-delete';
  12. import {
  13. useSWRxUserBookmarks, useSWRMUTxCurrentUserBookmarks,
  14. } from '~/stores/bookmark';
  15. import { useSWRxBookmarkFolderAndChild } from '~/stores/bookmark-folder';
  16. import { mutateAllPageInfo, useSWRMUTxPageInfo } from '~/stores/page';
  17. import { BookmarkFolderItem } from './BookmarkFolderItem';
  18. import { BookmarkItem } from './BookmarkItem';
  19. import styles from './BookmarkFolderTree.module.scss';
  20. // type DragItemDataType = {
  21. // bookmarkFolder: BookmarkFolderItems
  22. // level: number
  23. // parentFolder: BookmarkFolderItems | null
  24. // } & IPageHasId
  25. type Props = {
  26. isUserHomepage?: boolean,
  27. userId?: string,
  28. isOperable: boolean,
  29. }
  30. export const BookmarkFolderTree: React.FC<Props> = (props: Props) => {
  31. const { isUserHomepage, userId } = props;
  32. // const acceptedTypes: DragItemType[] = [DRAG_ITEM_TYPE.FOLDER, DRAG_ITEM_TYPE.BOOKMARK];
  33. const { t } = useTranslation();
  34. const router = useRouter();
  35. const isReadOnlyUser = useIsReadOnlyUser();
  36. const currentPage = useCurrentPageData();
  37. const { data: bookmarkFolders, mutate: mutateBookmarkFolders } = useSWRxBookmarkFolderAndChild(userId);
  38. const { data: userBookmarks, mutate: mutateUserBookmarks } = useSWRxUserBookmarks(userId ?? null);
  39. const { trigger: mutatePageInfo } = useSWRMUTxPageInfo(currentPage?._id ?? null);
  40. const { trigger: mutateCurrentUserBookmarks } = useSWRMUTxCurrentUserBookmarks();
  41. const { open: openDeleteModal } = usePageDeleteModalActions();
  42. const bookmarkFolderTreeMutation = useCallback(() => {
  43. mutateUserBookmarks();
  44. mutateCurrentUserBookmarks();
  45. mutatePageInfo();
  46. mutateBookmarkFolders();
  47. }, [mutateBookmarkFolders, mutatePageInfo, mutateCurrentUserBookmarks, mutateUserBookmarks]);
  48. const onClickDeleteMenuItemHandler = useCallback((pageToDelete: IPageToDeleteWithMeta) => {
  49. const pageDeletedHandler: OnDeletedFunction = (pathOrPathsToDelete, _isRecursively, isCompletely) => {
  50. if (typeof pathOrPathsToDelete !== 'string') return;
  51. toastSuccess(isCompletely ? t('deleted_pages_completely', { path: pathOrPathsToDelete }) : t('deleted_pages', { path: pathOrPathsToDelete }));
  52. bookmarkFolderTreeMutation();
  53. mutateAllPageInfo();
  54. if (pageToDelete.data._id === currentPage?._id && _isRecursively) {
  55. router.push(`/trash${currentPage.path}`);
  56. }
  57. };
  58. openDeleteModal([pageToDelete], { onDeleted: pageDeletedHandler });
  59. }, [openDeleteModal, t, bookmarkFolderTreeMutation, currentPage?._id, currentPage?.path, router]);
  60. /* TODO: update in bookmarks folder v2. */
  61. // const itemDropHandler = async(item: DragItemDataType, dragType: string | null | symbol) => {
  62. // if (dragType === DRAG_ITEM_TYPE.FOLDER) {
  63. // try {
  64. // await updateBookmarkFolder(item.bookmarkFolder._id, item.bookmarkFolder.name, null);
  65. // await mutateBookmarkData();
  66. // toastSuccess(t('toaster.update_successed', { target: t('bookmark_folder.bookmark_folder'), ns: 'commons' }));
  67. // }
  68. // catch (err) {
  69. // toastError(err);
  70. // }
  71. // }
  72. // else {
  73. // try {
  74. // await addBookmarkToFolder(item._id, null);
  75. // await mutateUserBookmarks();
  76. // toastSuccess(t('toaster.add_succeeded', { target: t('bookmark_folder.bookmark'), ns: 'commons' }));
  77. // }
  78. // catch (err) {
  79. // toastError(err);
  80. // }
  81. // }
  82. // };
  83. // const isDroppable = (item: DragItemDataType, dragType: string | null | symbol) => {
  84. // if (dragType === DRAG_ITEM_TYPE.FOLDER) {
  85. // const isRootFolder = item.level === 0;
  86. // return !isRootFolder;
  87. // }
  88. // const isRootBookmark = item.parentFolder == null;
  89. // return !isRootBookmark;
  90. // };
  91. return (
  92. <DndProvider backend={HTML5Backend}>
  93. <div className={`grw-folder-tree-container ${styles['grw-folder-tree-container']}`}>
  94. <ul className={`grw-foldertree ${styles['grw-foldertree']} list-group py-2`}>
  95. {bookmarkFolders?.map((bookmarkFolder) => {
  96. return (
  97. <BookmarkFolderItem
  98. key={bookmarkFolder._id}
  99. isReadOnlyUser={!!isReadOnlyUser}
  100. isOperable={props.isOperable}
  101. bookmarkFolder={bookmarkFolder}
  102. isOpen={false}
  103. level={0}
  104. root={bookmarkFolder._id}
  105. isUserHomepage={isUserHomepage}
  106. onClickDeleteMenuItemHandler={onClickDeleteMenuItemHandler}
  107. bookmarkFolderTreeMutation={bookmarkFolderTreeMutation}
  108. />
  109. );
  110. })}
  111. {userBookmarks?.map(userBookmark => (
  112. <div key={userBookmark?._id} className="grw-foldertree-item-container grw-root-bookmarks">
  113. <BookmarkItem
  114. isReadOnlyUser={!!isReadOnlyUser}
  115. isOperable={props.isOperable}
  116. bookmarkedPage={userBookmark}
  117. level={0}
  118. parentFolder={null}
  119. canMoveToRoot={false}
  120. onClickDeleteMenuItemHandler={onClickDeleteMenuItemHandler}
  121. bookmarkFolderTreeMutation={bookmarkFolderTreeMutation}
  122. />
  123. </div>
  124. ))}
  125. </ul>
  126. {/* TODO: update in bookmarks folder v2. Also delete drop_item_here in translation.json, if don't need it. */}
  127. {/* {bookmarkFolderData != null && bookmarkFolderData.length > 0 && (
  128. <DragAndDropWrapper
  129. useDropMode={true}
  130. type={acceptedTypes}
  131. onDropItem={itemDropHandler}
  132. isDropable={isDroppable}
  133. >
  134. <div className="grw-drop-item-area">
  135. <div className="d-flex flex-column align-items-center">
  136. {t('bookmark_folder.drop_item_here')}
  137. </div>
  138. </div>
  139. </DragAndDropWrapper>
  140. )} */}
  141. </div>
  142. </DndProvider>
  143. );
  144. };