Add ability to search for all accounts when creating a list in web UI

This commit is contained in:
Eugen Rochko 2024-11-22 20:13:42 +01:00
parent 86b42b0957
commit 1f6e616f17
6 changed files with 106 additions and 10 deletions

View File

@ -5,3 +5,16 @@ export const apiSubmitAccountNote = (id: string, value: string) =>
apiRequestPost<ApiRelationshipJSON>(`v1/accounts/${id}/note`, { apiRequestPost<ApiRelationshipJSON>(`v1/accounts/${id}/note`, {
comment: value, comment: value,
}); });
export const apiFollowAccount = (
id: string,
params?: {
reblogs: boolean;
},
) =>
apiRequestPost<ApiRelationshipJSON>(`v1/accounts/${id}/follow`, {
...params,
});
export const apiUnfollowAccount = (id: string) =>
apiRequestPost<ApiRelationshipJSON>(`v1/accounts/${id}/unfollow`);

View File

@ -9,10 +9,12 @@ import { useDebouncedCallback } from 'use-debounce';
import ListAltIcon from '@/material-icons/400-24px/list_alt.svg?react'; import ListAltIcon from '@/material-icons/400-24px/list_alt.svg?react';
import SquigglyArrow from '@/svg-icons/squiggly_arrow.svg?react'; import SquigglyArrow from '@/svg-icons/squiggly_arrow.svg?react';
import { fetchFollowing } from 'mastodon/actions/accounts'; import { fetchFollowing, fetchRelationships } from 'mastodon/actions/accounts';
import { importFetchedAccounts } from 'mastodon/actions/importer'; import { importFetchedAccounts } from 'mastodon/actions/importer';
import { fetchList } from 'mastodon/actions/lists'; import { fetchList } from 'mastodon/actions/lists';
import { openModal } from 'mastodon/actions/modal';
import { apiRequest } from 'mastodon/api'; import { apiRequest } from 'mastodon/api';
import { apiFollowAccount } from 'mastodon/api/accounts';
import { import {
apiGetAccounts, apiGetAccounts,
apiAddAccountToList, apiAddAccountToList,
@ -35,8 +37,8 @@ import { useAppDispatch, useAppSelector } from 'mastodon/store';
const messages = defineMessages({ const messages = defineMessages({
heading: { id: 'column.list_members', defaultMessage: 'Manage list members' }, heading: { id: 'column.list_members', defaultMessage: 'Manage list members' },
placeholder: { placeholder: {
id: 'lists.search_placeholder', id: 'lists.search',
defaultMessage: 'Search people you follow', defaultMessage: 'Search',
}, },
enterSearch: { id: 'lists.add_to_list', defaultMessage: 'Add to list' }, enterSearch: { id: 'lists.add_to_list', defaultMessage: 'Add to list' },
add: { id: 'lists.add_member', defaultMessage: 'Add' }, add: { id: 'lists.add_member', defaultMessage: 'Add' },
@ -53,17 +55,50 @@ const AccountItem: React.FC<{
onToggle: (accountId: string) => void; onToggle: (accountId: string) => void;
}> = ({ accountId, listId, partOfList, onToggle }) => { }> = ({ accountId, listId, partOfList, onToggle }) => {
const intl = useIntl(); const intl = useIntl();
const dispatch = useAppDispatch();
const account = useAppSelector((state) => state.accounts.get(accountId)); const account = useAppSelector((state) => state.accounts.get(accountId));
const relationship = useAppSelector((state) =>
accountId ? state.relationships.get(accountId) : undefined,
);
const following = relationship?.following || relationship?.requested;
useEffect(() => {
if (accountId) {
dispatch(fetchRelationships([accountId]));
}
}, [dispatch, accountId]);
const handleClick = useCallback(() => { const handleClick = useCallback(() => {
if (partOfList) { if (partOfList) {
void apiRemoveAccountFromList(listId, accountId); void apiRemoveAccountFromList(listId, accountId);
onToggle(accountId);
} else { } else {
void apiAddAccountToList(listId, accountId); if (following) {
void apiAddAccountToList(listId, accountId);
onToggle(accountId);
} else {
dispatch(
openModal({
modalType: 'CONFIRM_FOLLOW_TO_LIST',
modalProps: {
accountId,
onConfirm: () => {
apiFollowAccount(accountId)
.then(() => apiAddAccountToList(listId, accountId))
.then(() => {
onToggle(accountId);
return '';
})
.catch(() => {
// Nothing
});
},
},
}),
);
}
} }
}, [dispatch, accountId, following, listId, partOfList, onToggle]);
onToggle(accountId);
}, [accountId, listId, partOfList, onToggle]);
if (!account) { if (!account) {
return null; return null;
@ -193,8 +228,7 @@ const ListMembers: React.FC<{
signal: searchRequestRef.current.signal, signal: searchRequestRef.current.signal,
params: { params: {
q: value, q: value,
resolve: false, resolve: true,
following: true,
}, },
}) })
.then((data) => { .then((data) => {

View File

@ -0,0 +1,43 @@
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { useAppSelector } from 'mastodon/store';
import type { BaseConfirmationModalProps } from './confirmation_modal';
import { ConfirmationModal } from './confirmation_modal';
const messages = defineMessages({
title: {
id: 'confirmations.follow_to_list.title',
defaultMessage: 'Follow user?',
},
confirm: {
id: 'confirmations.follow_to_list.confirm',
defaultMessage: 'Follow and add to list',
},
});
export const ConfirmFollowToListModal: React.FC<
{
accountId: string;
onConfirm: () => void;
} & BaseConfirmationModalProps
> = ({ accountId, onConfirm, onClose }) => {
const intl = useIntl();
const account = useAppSelector((state) => state.accounts.get(accountId));
return (
<ConfirmationModal
title={intl.formatMessage(messages.title)}
message={
<FormattedMessage
id='confirmations.follow_to_list.message'
defaultMessage='You need to be following {name} to add them to a list.'
values={{ name: <strong>@{account?.acct}</strong> }}
/>
}
confirm={intl.formatMessage(messages.confirm)}
onConfirm={onConfirm}
onClose={onClose}
/>
);
};

View File

@ -6,3 +6,4 @@ export { ConfirmEditStatusModal } from './edit_status';
export { ConfirmUnfollowModal } from './unfollow'; export { ConfirmUnfollowModal } from './unfollow';
export { ConfirmClearNotificationsModal } from './clear_notifications'; export { ConfirmClearNotificationsModal } from './clear_notifications';
export { ConfirmLogOutModal } from './log_out'; export { ConfirmLogOutModal } from './log_out';
export { ConfirmFollowToListModal } from './follow_to_list';

View File

@ -36,6 +36,7 @@ import {
ConfirmUnfollowModal, ConfirmUnfollowModal,
ConfirmClearNotificationsModal, ConfirmClearNotificationsModal,
ConfirmLogOutModal, ConfirmLogOutModal,
ConfirmFollowToListModal,
} from './confirmation_modals'; } from './confirmation_modals';
import FocalPointModal from './focal_point_modal'; import FocalPointModal from './focal_point_modal';
import ImageModal from './image_modal'; import ImageModal from './image_modal';
@ -57,6 +58,7 @@ export const MODAL_COMPONENTS = {
'CONFIRM_UNFOLLOW': () => Promise.resolve({ default: ConfirmUnfollowModal }), 'CONFIRM_UNFOLLOW': () => Promise.resolve({ default: ConfirmUnfollowModal }),
'CONFIRM_CLEAR_NOTIFICATIONS': () => Promise.resolve({ default: ConfirmClearNotificationsModal }), 'CONFIRM_CLEAR_NOTIFICATIONS': () => Promise.resolve({ default: ConfirmClearNotificationsModal }),
'CONFIRM_LOG_OUT': () => Promise.resolve({ default: ConfirmLogOutModal }), 'CONFIRM_LOG_OUT': () => Promise.resolve({ default: ConfirmLogOutModal }),
'CONFIRM_FOLLOW_TO_LIST': () => Promise.resolve({ default: ConfirmFollowToListModal }),
'MUTE': MuteModal, 'MUTE': MuteModal,
'BLOCK': BlockModal, 'BLOCK': BlockModal,
'DOMAIN_BLOCK': DomainBlockModal, 'DOMAIN_BLOCK': DomainBlockModal,

View File

@ -205,6 +205,9 @@
"confirmations.edit.confirm": "Edit", "confirmations.edit.confirm": "Edit",
"confirmations.edit.message": "Editing now will overwrite the message you are currently composing. Are you sure you want to proceed?", "confirmations.edit.message": "Editing now will overwrite the message you are currently composing. Are you sure you want to proceed?",
"confirmations.edit.title": "Overwrite post?", "confirmations.edit.title": "Overwrite post?",
"confirmations.follow_to_list.confirm": "Follow and add to list",
"confirmations.follow_to_list.message": "You need to be following {name} to add them to a list.",
"confirmations.follow_to_list.title": "Follow user?",
"confirmations.logout.confirm": "Log out", "confirmations.logout.confirm": "Log out",
"confirmations.logout.message": "Are you sure you want to log out?", "confirmations.logout.message": "Are you sure you want to log out?",
"confirmations.logout.title": "Log out?", "confirmations.logout.title": "Log out?",
@ -492,7 +495,7 @@
"lists.replies_policy.list": "Members of the list", "lists.replies_policy.list": "Members of the list",
"lists.replies_policy.none": "No one", "lists.replies_policy.none": "No one",
"lists.save": "Save", "lists.save": "Save",
"lists.search_placeholder": "Search people you follow", "lists.search": "Search",
"lists.show_replies_to": "Include replies from list members to", "lists.show_replies_to": "Include replies from list members to",
"load_pending": "{count, plural, one {# new item} other {# new items}}", "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Loading…", "loading_indicator.label": "Loading…",