| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 |
- import React, { useCallback, useMemo, useState } from 'react';
- import { getCustomModifiers } from '@growi/ui/dist/utils';
- import { useTranslation } from 'next-i18next';
- import { DropdownItem, DropdownMenu, UncontrolledDropdown } from 'reactstrap';
- import { addBookmarkToFolder, toggleBookmark } from '~/client/util/bookmark-utils';
- import { toastError } from '~/client/util/toastr';
- import { IBookmarkInfo } from '~/interfaces/bookmark-info';
- import { useSWRBookmarkInfo, useSWRxUserBookmarks } from '~/stores/bookmark';
- import { useSWRxBookmarkFolderAndChild } from '~/stores/bookmark-folder';
- import { useCurrentUser } from '~/stores/context';
- import { useSWRxPageInfo } from '~/stores/page';
- import { BookmarkFolderMenuItem } from './BookmarkFolderMenuItem';
- export const BookmarkFolderMenu: React.FC<{children?: React.ReactNode, bookmarkInfo: IBookmarkInfo }> = ({ children, bookmarkInfo }): JSX.Element => {
- const { t } = useTranslation();
- const [selectedItem, setSelectedItem] = useState<string | null>(null);
- const [isOpen, setIsOpen] = useState(false);
- const { data: currentUser } = useCurrentUser();
- const { data: bookmarkFolders, mutate: mutateBookmarkFolders } = useSWRxBookmarkFolderAndChild(currentUser?._id);
- const { mutate: mutateBookmarkInfo } = useSWRBookmarkInfo(bookmarkInfo.pageId);
- const { mutate: mutateUserBookmarks } = useSWRxUserBookmarks(currentUser?._id);
- const { mutate: mutatePageInfo } = useSWRxPageInfo(bookmarkInfo.pageId);
- const isBookmarked = bookmarkInfo.isBookmarked ?? false;
- const isBookmarkFolderExists = useMemo((): boolean => {
- return bookmarkFolders != null && bookmarkFolders.length > 0;
- }, [bookmarkFolders]);
- const toggleBookmarkHandler = useCallback(async() => {
- try {
- await toggleBookmark(bookmarkInfo.pageId, isBookmarked);
- }
- catch (err) {
- toastError(err);
- }
- }, [bookmarkInfo.pageId, isBookmarked]);
- const onUnbookmarkHandler = useCallback(async() => {
- await toggleBookmarkHandler();
- setIsOpen(false);
- setSelectedItem(null);
- mutateUserBookmarks();
- mutateBookmarkInfo();
- mutateBookmarkFolders();
- mutatePageInfo();
- }, [mutateBookmarkFolders, mutateBookmarkInfo, mutatePageInfo, mutateUserBookmarks, toggleBookmarkHandler]);
- const toggleHandler = useCallback(async() => {
- setIsOpen(!isOpen);
- if (isOpen && bookmarkFolders != null) {
- bookmarkFolders.forEach((bookmarkFolder) => {
- bookmarkFolder.bookmarks.forEach((bookmark) => {
- if (bookmark.page._id === bookmarkInfo.pageId) {
- setSelectedItem(bookmarkFolder._id);
- }
- });
- });
- }
- if (selectedItem == null) {
- setSelectedItem('root');
- }
- if (!isOpen && !isBookmarked) {
- try {
- await toggleBookmarkHandler();
- mutateUserBookmarks();
- mutateBookmarkInfo();
- mutatePageInfo();
- }
- catch (err) {
- toastError(err);
- }
- }
- },
- [isOpen, bookmarkFolders, selectedItem, isBookmarked, bookmarkInfo.pageId, toggleBookmarkHandler, mutateUserBookmarks, mutateBookmarkInfo, mutatePageInfo]);
- const onMenuItemClickHandler = useCallback(async(e, itemId: string) => {
- e.stopPropagation();
- setSelectedItem(itemId);
- try {
- await addBookmarkToFolder(bookmarkInfo.pageId, itemId === 'root' ? null : itemId);
- mutateUserBookmarks();
- mutateBookmarkFolders();
- mutateBookmarkInfo();
- }
- catch (err) {
- toastError(err);
- }
- }, [bookmarkInfo.pageId, mutateUserBookmarks, mutateBookmarkFolders, mutateBookmarkInfo]);
- const renderBookmarkMenuItem = () => {
- return (
- <>
- <DropdownItem
- toggle={false}
- onClick={onUnbookmarkHandler}
- className={'grw-bookmark-folder-menu-item text-danger'}
- >
- <i className="fa fa-bookmark"></i>{' '}
- <span className="mx-2 ">
- {t('bookmark_folder.cancel_bookmark')}
- </span>
- </DropdownItem>
- {isBookmarkFolderExists && (
- <>
- <DropdownItem divider />
- <div key="root">
- <div
- className="dropdown-item grw-bookmark-folder-menu-item list-group-item list-group-item-action border-0 py-0"
- tabIndex={0}
- role="menuitem"
- onClick={e => onMenuItemClickHandler(e, 'root')}
- >
- <BookmarkFolderMenuItem
- itemId="root"
- itemName={t('bookmark_folder.root')}
- isSelected={selectedItem === 'root'}
- />
- </div>
- </div>
- {bookmarkFolders?.map(folder => (
- <div key={folder._id}>
- <div
- className="dropdown-item grw-bookmark-folder-menu-item list-group-item list-group-item-action border-0 py-0"
- style={{ paddingLeft: '40px' }}
- tabIndex={0}
- role="menuitem"
- onClick={e => onMenuItemClickHandler(e, folder._id)}
- >
- <BookmarkFolderMenuItem
- itemId={folder._id}
- itemName={folder.name}
- isSelected={selectedItem === folder._id}
- />
- </div>
- {folder.children?.map(child => (
- <div key={child._id}>
- <div
- className='dropdown-item grw-bookmark-folder-menu-item list-group-item list-group-item-action border-0 py-0'
- style={{ paddingLeft: '60px' }}
- tabIndex={0}
- role="menuitem"
- onClick={e => onMenuItemClickHandler(e, child._id)}
- >
- <BookmarkFolderMenuItem
- itemId={child._id}
- itemName={child.name}
- isSelected={selectedItem === child._id}
- />
- </div>
- </div>
- ))}
- </div>
- ))}
- </>
- )}
- </>
- );
- };
- return (
- <UncontrolledDropdown
- isOpen={isOpen}
- onToggle={toggleHandler}
- direction={isBookmarkFolderExists ? 'up' : 'down'}
- className='grw-bookmark-folder-dropdown'
- >
- {children}
- <DropdownMenu
- right
- persist
- positionFixed
- className='grw-bookmark-folder-menu'
- modifiers={getCustomModifiers(true)}
- >
- { renderBookmarkMenuItem() }
- </DropdownMenu>
- </UncontrolledDropdown>
- );
- };
|