pl-fe: Support kmyblue bookmark folders
Signed-off-by: Nicole Mikołajczyk <git@mkljczk.pl>
This commit is contained in:
@ -1170,6 +1170,30 @@ class PlApiClient {
|
||||
|
||||
return v.parse(bookmarkFolderSchema, response.json);
|
||||
},
|
||||
|
||||
/**
|
||||
* Requires features{@link Features.bookmarkFoldersMultiple}.
|
||||
*/
|
||||
addBookmarkToFolder: async (statusId: string, folderId: string) => {
|
||||
const response = await this.request <{}>(
|
||||
`/api/v1/bookmark_categories/${folderId}/statuses`,
|
||||
{ method: 'POST', params: { status_ids: [statusId] } },
|
||||
);
|
||||
|
||||
return response.json;
|
||||
},
|
||||
|
||||
/**
|
||||
* Requires features{@link Features.bookmarkFoldersMultiple}.
|
||||
*/
|
||||
removeBookmarkFromFolder: async (statusId: string, folderId: string) => {
|
||||
const response = await this.request<{}>(
|
||||
`/api/v1/bookmark_categories/${folderId}/statuses`,
|
||||
{ method: 'DELETE', params: { status_ids: [statusId] } },
|
||||
);
|
||||
|
||||
return response.json;
|
||||
},
|
||||
};
|
||||
|
||||
public readonly settings = {
|
||||
@ -2593,7 +2617,7 @@ class PlApiClient {
|
||||
* Requires features{@link Features.bookmarkFoldersMultiple}.
|
||||
*/
|
||||
getStatusBookmarkFolders: async (statusId: string) => {
|
||||
const response = await this.request(`/api/v1/statuses/${statusId}/categories`, { method: 'GET' });
|
||||
const response = await this.request(`/api/v1/statuses/${statusId}/bookmark_categories`, { method: 'GET' });
|
||||
|
||||
return v.parse(filteredArray(bookmarkFolderSchema), response.json);
|
||||
},
|
||||
|
||||
@ -2,6 +2,7 @@ import React, { useCallback, useState } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { bookmark } from 'pl-fe/actions/interactions';
|
||||
import { ListItem } from 'pl-fe/components/list';
|
||||
import { RadioGroup, RadioItem } from 'pl-fe/components/radio';
|
||||
import Emoji from 'pl-fe/components/ui/emoji';
|
||||
import HStack from 'pl-fe/components/ui/hstack';
|
||||
@ -9,10 +10,12 @@ import Icon from 'pl-fe/components/ui/icon';
|
||||
import Modal from 'pl-fe/components/ui/modal';
|
||||
import Spinner from 'pl-fe/components/ui/spinner';
|
||||
import Stack from 'pl-fe/components/ui/stack';
|
||||
import Toggle from 'pl-fe/components/ui/toggle';
|
||||
import NewFolderForm from 'pl-fe/features/bookmark-folders/components/new-folder-form';
|
||||
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
import { useAppSelector } from 'pl-fe/hooks/use-app-selector';
|
||||
import { useBookmarkFolders } from 'pl-fe/queries/statuses/use-bookmark-folders';
|
||||
import { useFeatures } from 'pl-fe/hooks/use-features';
|
||||
import { useAddBookmarkToFolder, useBookmarkFolders, useRemoveBookmarkFromFolder, useStatusBookmarkFolders } from 'pl-fe/queries/statuses/use-bookmark-folders';
|
||||
import { makeGetStatus } from 'pl-fe/selectors';
|
||||
|
||||
import type { BaseModalProps } from '../modal-root';
|
||||
@ -25,10 +28,14 @@ const SelectBookmarkFolderModal: React.FC<SelectBookmarkFolderModalProps & BaseM
|
||||
const getStatus = useCallback(makeGetStatus(), []);
|
||||
const status = useAppSelector(state => getStatus(state, { id: statusId }))!;
|
||||
const dispatch = useAppDispatch();
|
||||
const features = useFeatures();
|
||||
|
||||
const [selectedFolder, setSelectedFolder] = useState(status.bookmark_folder);
|
||||
|
||||
const { isFetching, data: bookmarkFolders } = useBookmarkFolders(data => data);
|
||||
const { data: selectedBookmarkFolders, isPending: fetchingSelectedBookmarkFolders } = useStatusBookmarkFolders(statusId);
|
||||
const { mutate: addBookmarkToFolder, isPending: addingBookmarkToFolder } = useAddBookmarkToFolder(statusId);
|
||||
const { mutate: removeBookmarkFromFolder, isPending: removingBookmarkFromFolder } = useRemoveBookmarkFromFolder(statusId);
|
||||
|
||||
const onChange: React.ChangeEventHandler<HTMLInputElement> = e => {
|
||||
const folderId = e.target.value;
|
||||
@ -43,23 +50,19 @@ const SelectBookmarkFolderModal: React.FC<SelectBookmarkFolderModalProps & BaseM
|
||||
onClose('SELECT_BOOKMARK_FOLDER');
|
||||
};
|
||||
|
||||
const items = [
|
||||
<RadioItem
|
||||
key='all'
|
||||
label={
|
||||
<HStack alignItems='center' space={2}>
|
||||
<Icon src={require('@tabler/icons/outline/bookmarks.svg')} size={20} />
|
||||
<span><FormattedMessage id='bookmark_folders.all_bookmarks' defaultMessage='All bookmarks' /></span>
|
||||
</HStack>
|
||||
}
|
||||
checked={selectedFolder === null}
|
||||
value=''
|
||||
/>,
|
||||
];
|
||||
const toggleBookmarkFolder = (folderId: string) => {
|
||||
if (selectedBookmarkFolders?.includes(folderId)) {
|
||||
removeBookmarkFromFolder(folderId);
|
||||
} else {
|
||||
addBookmarkToFolder(folderId);
|
||||
}
|
||||
};
|
||||
|
||||
if (!isFetching) {
|
||||
items.push(...((bookmarkFolders || []).map((folder) => (
|
||||
<RadioItem
|
||||
let items;
|
||||
|
||||
if (features.bookmarkFoldersMultiple) {
|
||||
items = (bookmarkFolders || []).map((folder) => (
|
||||
<ListItem
|
||||
key={folder.id}
|
||||
label={
|
||||
<HStack alignItems='center' space={2}>
|
||||
@ -73,10 +76,50 @@ const SelectBookmarkFolderModal: React.FC<SelectBookmarkFolderModalProps & BaseM
|
||||
<span>{folder.name}</span>
|
||||
</HStack>
|
||||
}
|
||||
checked={selectedFolder === folder.id}
|
||||
value={folder.id}
|
||||
/>
|
||||
))));
|
||||
>
|
||||
<Toggle
|
||||
checked={selectedBookmarkFolders?.includes(folder.id)}
|
||||
onChange={() => toggleBookmarkFolder(folder.id)}
|
||||
disabled={fetchingSelectedBookmarkFolders || addingBookmarkToFolder || removingBookmarkFromFolder}
|
||||
/>
|
||||
</ListItem>
|
||||
));
|
||||
} else {
|
||||
items = [
|
||||
<RadioItem
|
||||
key='all'
|
||||
label={
|
||||
<HStack alignItems='center' space={2}>
|
||||
<Icon src={require('@tabler/icons/outline/bookmarks.svg')} size={20} />
|
||||
<span><FormattedMessage id='bookmark_folders.all_bookmarks' defaultMessage='All bookmarks' /></span>
|
||||
</HStack>
|
||||
}
|
||||
checked={selectedFolder === null}
|
||||
value=''
|
||||
/>,
|
||||
];
|
||||
|
||||
if (!isFetching) {
|
||||
items.push(...((bookmarkFolders || []).map((folder) => (
|
||||
<RadioItem
|
||||
key={folder.id}
|
||||
label={
|
||||
<HStack alignItems='center' space={2}>
|
||||
{folder.emoji ? (
|
||||
<Emoji
|
||||
emoji={folder.emoji}
|
||||
src={folder.emoji_url || undefined}
|
||||
className='size-5 flex-none'
|
||||
/>
|
||||
) : <Icon src={require('@tabler/icons/outline/folder.svg')} size={20} />}
|
||||
<span>{folder.name}</span>
|
||||
</HStack>
|
||||
}
|
||||
checked={selectedFolder === folder.id}
|
||||
value={folder.id}
|
||||
/>
|
||||
))));
|
||||
}
|
||||
}
|
||||
|
||||
const body = isFetching ? <Spinner /> : (
|
||||
|
||||
@ -63,4 +63,44 @@ const useUpdateBookmarkFolder = (folderId: string) => {
|
||||
});
|
||||
};
|
||||
|
||||
export { useBookmarkFolders, useBookmarkFolder, useCreateBookmarkFolder, useDeleteBookmarkFolder, useUpdateBookmarkFolder };
|
||||
const useStatusBookmarkFolders = (statusId: string) => {
|
||||
const client = useClient();
|
||||
const features = useFeatures();
|
||||
|
||||
return useQuery({
|
||||
queryKey: ['bookmarkFolders', 'status', statusId],
|
||||
queryFn: () => client.statuses.getStatusBookmarkFolders(statusId).then(response => response.map((folder) => folder.id)),
|
||||
enabled: features.bookmarkFoldersMultiple,
|
||||
});
|
||||
};
|
||||
|
||||
const useAddBookmarkToFolder = (statusId: string) => {
|
||||
const client = useClient();
|
||||
|
||||
return useMutation({
|
||||
mutationKey: ['bookmarkFolders', 'add', statusId],
|
||||
mutationFn: (folderId: string) => client.myAccount.addBookmarkToFolder(statusId, folderId),
|
||||
onSettled: () => queryClient.invalidateQueries({ queryKey: ['bookmarkFolders', 'status', statusId] }),
|
||||
});
|
||||
};
|
||||
|
||||
const useRemoveBookmarkFromFolder = (statusId: string) => {
|
||||
const client = useClient();
|
||||
|
||||
return useMutation({
|
||||
mutationKey: ['bookmarkFolders', 'remove', statusId],
|
||||
mutationFn: (folderId: string) => client.myAccount.removeBookmarkFromFolder(statusId, folderId),
|
||||
onSettled: () => queryClient.invalidateQueries({ queryKey: ['bookmarkFolders', 'status', statusId] }),
|
||||
});
|
||||
};
|
||||
|
||||
export {
|
||||
useBookmarkFolders,
|
||||
useBookmarkFolder,
|
||||
useCreateBookmarkFolder,
|
||||
useDeleteBookmarkFolder,
|
||||
useUpdateBookmarkFolder,
|
||||
useStatusBookmarkFolders,
|
||||
useAddBookmarkToFolder,
|
||||
useRemoveBookmarkFromFolder,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user