import { DragDropContext, Draggable, Droppable } from '@hello-pangea/dnd'; import { Box, Button, Card, Group, Stack, Text, TextInput } from '@mantine/core'; import { isNotEmpty, useForm } from '@mantine/form'; import { useDebouncedValue, useDisclosure } from '@mantine/hooks'; import { AddItemModal, NoItemsFound, SettingsHeader } from 'components'; import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks'; import { useEffect, useState } from 'react'; import { textInputClasses } from 'styles'; import type { Bookmark, BookmarkGroup } from 'types'; import DebouncedGroupSettingsItem from './DebouncedGroupSettingsItem'; const BookmarkSettings = () => { const defaultGroup = { id: null, categoryName: '', categoryIndex: 0, filterName: '', }; const form = useForm({ initialValues: defaultGroup, validate: { categoryName: isNotEmpty('Category name is required'), filterName: isNotEmpty('Filter name is required'), }, }); const bookmarksEndpoint = 'api/bookmarks'; const { data: bookmarkData, isFetched: bookmarksIsFetched } = useQueryAPI({ endpoint: bookmarksEndpoint, }); const [bookmarks, setBookmarks] = useState([]); const categoriesEndpoint = 'api/bookmarkCategories'; const { data: groupData, isFetched: groupsIsFetched } = useQueryAPI({ endpoint: categoriesEndpoint, }); const [dragging, setDragging] = useState(false); const [groups, setGroups] = useState([]); const [groupList, setGroupList] = useState([]); const { isMobile, reorder, theme } = useCommonHooks(); const { mutateAsync } = useMutationAPI(); const [searchValue, setSearchValue] = useState(''); const [debouncedGroupSearch] = useDebouncedValue(searchValue, 500); const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false); const [isLoading, setIsLoading] = useState(false); const handleClose = () => { closeModal(); form.reset(); }; function onDragEnd(result: any) { if (!result.destination) { return; } if (result.destination.index === result.source.index) { return; } const items = reorder(groups, result.source.index, result.destination.index); setGroupList( items.map((item: any, index: number) => { return { ...item, index: index, }; }), ); } useEffect(() => { if (bookmarkData && bookmarksIsFetched) { setBookmarks(bookmarkData); } }, [bookmarksIsFetched, bookmarkData]); useEffect(() => { if (groupData && groupsIsFetched) { const foundBookmarkGroups = [ ...new Set( bookmarks .filter( (a: Bookmark) => a.name.toLowerCase().includes(debouncedGroupSearch.toLowerCase()) || a.url.toLowerCase().includes(debouncedGroupSearch.toLowerCase()), ) .map( (a: Bookmark) => groupData.filter( (b: BookmarkGroup) => b.categoryName.toLowerCase() === a.category.toLowerCase(), )[0], ), ), ]; const foundGroups = groupData.filter((a: BookmarkGroup) => a.categoryName.toLowerCase().includes(debouncedGroupSearch.toLowerCase()), ); const groupList = [...new Set([...foundBookmarkGroups, ...foundGroups])].sort( (a: BookmarkGroup, b: BookmarkGroup) => a.categoryIndex > b.categoryIndex ? 1 : -1, ); setGroups(groupList); } if (debouncedGroupSearch === searchValue) { setIsLoading(false); } }, [groupData, groupsIsFetched, debouncedGroupSearch]); useEffect(() => { if (groupList.length > 0 && groupList !== groups) { mutateAsync({ method: 'PATCH', endpoint: 'api/bookmarkCategoryOrder', body: groupList, }); } }, [groupList]); return ( { mutateAsync({ method: 'POST', endpoint: categoriesEndpoint, body: { ...values, categoryIndex: groups.length, }, }); handleClose(); })} > } /> 0 ? setDragging : undefined} openModal={openModal} title={'Bookmarks'} tooltip={{ title: 'Bookmarks are the links that will be displayed on the homepage.', highlightList: [ 'Bookmark', 'Bookmarks', 'Group', 'Groups', 'Link', 'Links', 'Category', 'Categories', ], description: 'Bookmarks can only belong to a single category, and will be displayed under that category on the homepage.', }} searchValue={searchValue} setSearchValue={setSearchValue} searchPlaceholder={'Search Bookmark Groups...'} isLoading={isLoading} setIsLoading={setIsLoading} /> {dragging ? ( {(provided) => ( {groups?.map((group: BookmarkGroup) => ( {(provided) => ( Name {group.categoryName} Filter Name {group.filterName} )} ))} {provided.placeholder} )} ) : ( {groups.length > 0 ? ( groups?.map((group: BookmarkGroup) => ( a.category === group.categoryName) .sort((a: Bookmark, b: Bookmark) => (a.index > b.index ? 1 : -1))} searchTerm={searchValue} /> )) ) : ( )} )} ); }; export default BookmarkSettings;