BookmarkFolderTree.tsx 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. import { useCallback } from 'react';
  2. import { useTranslation } from 'next-i18next';
  3. import { useDrop } from 'react-dnd';
  4. import { apiv3Post, apiv3Put } from '~/client/util/apiv3-client';
  5. import { toastError, toastSuccess } from '~/client/util/toastr';
  6. import { BookmarkFolderItems, DragItemType, DRAG_ITEM_TYPE } from '~/interfaces/bookmark-info';
  7. import { IPageHasId, IPageToDeleteWithMeta } from '~/interfaces/page';
  8. import { OnDeletedFunction } from '~/interfaces/ui';
  9. import { useSWRBookmarkInfo, useSWRxCurrentUserBookmarks } from '~/stores/bookmark';
  10. import { useSWRxBookamrkFolderAndChild } from '~/stores/bookmark-folder';
  11. import { usePageDeleteModal } from '~/stores/modal';
  12. import { useSWRxCurrentPage } from '~/stores/page';
  13. import BookmarkFolderItem from './BookmarkFolderItem';
  14. import BookmarkItem from './BookmarkItem';
  15. import styles from './BookmarkFolderTree.module.scss';
  16. type BookmarkFolderTreeProps = {
  17. isUserHomePage?: boolean
  18. }
  19. type DragItemDataType = {
  20. bookmarkFolder: BookmarkFolderItems
  21. level: number
  22. parentFolder: BookmarkFolderItems | null
  23. } & IPageHasId
  24. const BookmarkFolderTree = (props: BookmarkFolderTreeProps): JSX.Element => {
  25. const acceptedTypes: DragItemType[] = [DRAG_ITEM_TYPE.FOLDER, DRAG_ITEM_TYPE.BOOKMARK];
  26. const { t } = useTranslation();
  27. const { isUserHomePage } = props;
  28. const { data: currentPage } = useSWRxCurrentPage();
  29. const { data: bookmarkFolderData, mutate: mutateBookamrkData } = useSWRxBookamrkFolderAndChild();
  30. const { data: userBookmarks, mutate: mutateUserBookmarks } = useSWRxCurrentUserBookmarks();
  31. const { mutate: mutateBookmarkInfo } = useSWRBookmarkInfo(currentPage?._id);
  32. const { open: openDeleteModal } = usePageDeleteModal();
  33. const onUnbookmarkHandler = useCallback(() => {
  34. mutateUserBookmarks();
  35. mutateBookmarkInfo();
  36. }, [mutateBookmarkInfo, mutateUserBookmarks]);
  37. const onClickDeleteBookmarkHandler = useCallback((pageToDelete: IPageToDeleteWithMeta) => {
  38. const pageDeletedHandler: OnDeletedFunction = (pathOrPathsToDelete, _isRecursively, isCompletely) => {
  39. if (typeof pathOrPathsToDelete !== 'string') {
  40. return;
  41. }
  42. const path = pathOrPathsToDelete;
  43. if (isCompletely) {
  44. toastSuccess(t('deleted_pages_completely', { path }));
  45. }
  46. else {
  47. toastSuccess(t('deleted_pages', { path }));
  48. }
  49. mutateUserBookmarks();
  50. mutateBookmarkInfo();
  51. mutateBookamrkData();
  52. };
  53. openDeleteModal([pageToDelete], { onDeleted: pageDeletedHandler });
  54. }, [mutateBookmarkInfo, mutateBookamrkData, mutateUserBookmarks, openDeleteModal, t]);
  55. const itemDropHandler = async(item: DragItemDataType, dragType: string | null | symbol) => {
  56. if (dragType === DRAG_ITEM_TYPE.FOLDER) {
  57. try {
  58. await apiv3Put('/bookmark-folder', { bookmarkFolderId: item.bookmarkFolder._id, name: item.bookmarkFolder.name, parent: null });
  59. await mutateBookamrkData();
  60. toastSuccess(t('toaster.update_successed', { target: t('bookmark_folder.bookmark_folder'), ns: 'commons' }));
  61. }
  62. catch (err) {
  63. toastError(err);
  64. }
  65. }
  66. else {
  67. try {
  68. await apiv3Post('/bookmark-folder/add-boookmark-to-folder', { pageId: item._id, folderId: null });
  69. await mutateUserBookmarks();
  70. toastSuccess(t('toaster.add_succeeded', { target: t('bookmark_folder.bookmark'), ns: 'commons' }));
  71. }
  72. catch (err) {
  73. toastError(err);
  74. }
  75. }
  76. };
  77. const isDroppable = (item: DragItemDataType, dragType: string | null | symbol) => {
  78. if (dragType === DRAG_ITEM_TYPE.FOLDER) {
  79. const isRootFolder = item.level === 0;
  80. return !isRootFolder;
  81. }
  82. const isRootBookmark = item.parentFolder == null;
  83. return !isRootBookmark;
  84. };
  85. const [{ isOver, canDrop }, dropRef] = useDrop(() => ({
  86. accept: acceptedTypes,
  87. drop: (item: DragItemDataType, monitor) => {
  88. const dragType = monitor.getItemType();
  89. itemDropHandler(item, dragType);
  90. },
  91. canDrop: (item: DragItemDataType, monitor) => {
  92. const dragType = monitor.getItemType();
  93. return isDroppable(item, dragType);
  94. },
  95. collect: monitor => ({
  96. isOver: monitor.isOver({ shallow: true }) && monitor.canDrop(),
  97. canDrop: monitor.canDrop(),
  98. }),
  99. }));
  100. return (
  101. <>
  102. <div className={`grw-folder-tree-container ${styles['grw-folder-tree-container']}` } >
  103. <ul className={`grw-foldertree ${styles['grw-foldertree']} list-group px-2 py-2`}>
  104. {bookmarkFolderData?.map((item) => {
  105. return (
  106. <BookmarkFolderItem
  107. key={item._id}
  108. bookmarkFolder={item}
  109. isOpen={false}
  110. level={0}
  111. root={item._id}
  112. isUserHomePage={isUserHomePage}
  113. />
  114. );
  115. })}
  116. {userBookmarks?.map(page => (
  117. <div key={page._id} className="grw-foldertree-item-container grw-root-bookmarks">
  118. <BookmarkItem
  119. bookmarkedPage={page}
  120. key={page._id}
  121. onUnbookmarked={onUnbookmarkHandler}
  122. onRenamed={mutateUserBookmarks}
  123. onClickDeleteMenuItem={onClickDeleteBookmarkHandler}
  124. parentFolder={null}
  125. />
  126. </div>
  127. ))}
  128. </ul>
  129. { bookmarkFolderData && bookmarkFolderData.length > 0 && (
  130. <div ref={(c) => { dropRef(c) }} className= 'grw-drop-item-area' >
  131. { canDrop && isOver && (
  132. <div className='grw-accept-drop-item' >{t('bookmark_folder.drop_item_here')}</div>
  133. )}
  134. </div>
  135. ) }
  136. </div>
  137. </>
  138. );
  139. };
  140. export default BookmarkFolderTree;