Files
ncd-fe/src/features/bookmarks/index.tsx
marcin mikołajczak ce67cb537f Fix padding for black theme
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2024-06-04 11:52:54 +02:00

126 lines
5.0 KiB
TypeScript

import { OrderedSet as ImmutableOrderedSet } from 'immutable';
import debounce from 'lodash/debounce';
import React from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { useHistory } from 'react-router-dom';
import { fetchBookmarkedStatuses, expandBookmarkedStatuses } from 'soapbox/actions/bookmarks';
import { openModal } from 'soapbox/actions/modals';
import { useBookmarkFolder, useDeleteBookmarkFolder } from 'soapbox/api/hooks';
import DropdownMenu from 'soapbox/components/dropdown-menu';
import PullToRefresh from 'soapbox/components/pull-to-refresh';
import StatusList from 'soapbox/components/status-list';
import { Column } from 'soapbox/components/ui';
import { useAppSelector, useAppDispatch, useTheme } from 'soapbox/hooks';
import { useIsMobile } from 'soapbox/hooks/useIsMobile';
import toast from 'soapbox/toast';
const messages = defineMessages({
heading: { id: 'column.bookmarks', defaultMessage: 'Bookmarks' },
editFolder: { id: 'bookmarks.edit_folder', defaultMessage: 'Edit folder' },
deleteFolder: { id: 'bookmarks.delete_folder', defaultMessage: 'Delete folder' },
deleteFolderHeading: { id: 'confirmations.delete_bookmark_folder.heading', defaultMessage: 'Delete "{name}" folder?' },
deleteFolderMessage: { id: 'confirmations.delete_bookmark_folder.message', defaultMessage: 'Are you sure you want to delete the folder? The bookmarks will still be stored.' },
deleteFolderConfirm: { id: 'confirmations.delete_bookmark_folder.confirm', defaultMessage: 'Delete folder' },
deleteFolderSuccess: { id: 'bookmarks.delete_folder.success', defaultMessage: 'Folder deleted' },
deleteFolderFail: { id: 'bookmarks.delete_folder.fail', defaultMessage: 'Failed to delete folder' },
});
const handleLoadMore = debounce((dispatch, folderId) => {
dispatch(expandBookmarkedStatuses(folderId));
}, 300, { leading: true });
interface IBookmarks {
params?: {
id?: string;
};
}
const Bookmarks: React.FC<IBookmarks> = ({ params }) => {
const dispatch = useAppDispatch();
const intl = useIntl();
const history = useHistory();
const theme = useTheme();
const isMobile = useIsMobile();
const folderId = params?.id;
const { bookmarkFolder: folder } = useBookmarkFolder(folderId);
const { deleteBookmarkFolder } = useDeleteBookmarkFolder();
const bookmarksKey = folderId ? `bookmarks:${folderId}` : 'bookmarks';
const statusIds = useAppSelector((state) => state.status_lists.get(bookmarksKey)?.items || ImmutableOrderedSet<string>());
const isLoading = useAppSelector((state) => state.status_lists.get(bookmarksKey)?.isLoading === true);
const hasMore = useAppSelector((state) => !!state.status_lists.get(bookmarksKey)?.next);
React.useEffect(() => {
dispatch(fetchBookmarkedStatuses(folderId));
}, [folderId]);
const handleRefresh = () => dispatch(fetchBookmarkedStatuses(folderId));
const handleEditFolder = () => {
dispatch(openModal('EDIT_BOOKMARK_FOLDER', { folderId }));
};
const handleDeleteFolder = () => {
dispatch(openModal('CONFIRM', {
heading: intl.formatMessage(messages.deleteFolderHeading, { name: folder?.name }),
message: intl.formatMessage(messages.deleteFolderMessage),
confirm: intl.formatMessage(messages.deleteFolderConfirm),
onConfirm: () => {
deleteBookmarkFolder(folderId!, {
onSuccess() {
toast.success(messages.deleteFolderSuccess);
history.push('/bookmarks');
},
onError() {
toast.error(messages.deleteFolderFail);
},
});
},
}));
};
const emptyMessage = folderId
? <FormattedMessage id='empty_column.bookmarks.folder' defaultMessage="You don't have any bookmarks in this folder yet. When you add one, it will show up here." />
: <FormattedMessage id='empty_column.bookmarks' defaultMessage="You don't have any bookmarks yet. When you add one, it will show up here." />;
const items = folderId ? [
{
text: intl.formatMessage(messages.editFolder),
action: handleEditFolder,
icon: require('@tabler/icons/outline/edit.svg'),
},
{
text: intl.formatMessage(messages.deleteFolder),
action: handleDeleteFolder,
icon: require('@tabler/icons/outline/trash.svg'),
},
] : [];
return (
<Column
label={folder ? folder.name : intl.formatMessage(messages.heading)}
action={<DropdownMenu items={items} src={require('@tabler/icons/outline/dots-vertical.svg')} />}
transparent={!isMobile}
>
<PullToRefresh onRefresh={handleRefresh}>
<StatusList
className='black:p-4 black:sm:p-0'
statusIds={statusIds}
scrollKey='bookmarked_statuses'
hasMore={hasMore}
isLoading={typeof isLoading === 'boolean' ? isLoading : true}
onLoadMore={() => handleLoadMore(dispatch, folderId)}
emptyMessage={emptyMessage}
divideType={(theme === 'black' || isMobile) ? 'border' : 'space'}
/>
</PullToRefresh>
</Column>
);
};
export { Bookmarks as default };