Add useSuggest hook
https://gitlab.com/soapbox-pub/soapbox/-/issues/1483
This commit is contained in:
parent
78436172db
commit
31e5f860d9
6 changed files with 92 additions and 79 deletions
|
@ -75,14 +75,6 @@ const ADMIN_REMOVE_PERMISSION_GROUP_REQUEST = 'ADMIN_REMOVE_PERMISSION_GROUP_REQ
|
||||||
const ADMIN_REMOVE_PERMISSION_GROUP_SUCCESS = 'ADMIN_REMOVE_PERMISSION_GROUP_SUCCESS';
|
const ADMIN_REMOVE_PERMISSION_GROUP_SUCCESS = 'ADMIN_REMOVE_PERMISSION_GROUP_SUCCESS';
|
||||||
const ADMIN_REMOVE_PERMISSION_GROUP_FAIL = 'ADMIN_REMOVE_PERMISSION_GROUP_FAIL';
|
const ADMIN_REMOVE_PERMISSION_GROUP_FAIL = 'ADMIN_REMOVE_PERMISSION_GROUP_FAIL';
|
||||||
|
|
||||||
const ADMIN_USERS_SUGGEST_REQUEST = 'ADMIN_USERS_SUGGEST_REQUEST';
|
|
||||||
const ADMIN_USERS_SUGGEST_SUCCESS = 'ADMIN_USERS_SUGGEST_SUCCESS';
|
|
||||||
const ADMIN_USERS_SUGGEST_FAIL = 'ADMIN_USERS_SUGGEST_FAIL';
|
|
||||||
|
|
||||||
const ADMIN_USERS_UNSUGGEST_REQUEST = 'ADMIN_USERS_UNSUGGEST_REQUEST';
|
|
||||||
const ADMIN_USERS_UNSUGGEST_SUCCESS = 'ADMIN_USERS_UNSUGGEST_SUCCESS';
|
|
||||||
const ADMIN_USERS_UNSUGGEST_FAIL = 'ADMIN_USERS_UNSUGGEST_FAIL';
|
|
||||||
|
|
||||||
const ADMIN_USER_INDEX_EXPAND_FAIL = 'ADMIN_USER_INDEX_EXPAND_FAIL';
|
const ADMIN_USER_INDEX_EXPAND_FAIL = 'ADMIN_USER_INDEX_EXPAND_FAIL';
|
||||||
const ADMIN_USER_INDEX_EXPAND_REQUEST = 'ADMIN_USER_INDEX_EXPAND_REQUEST';
|
const ADMIN_USER_INDEX_EXPAND_REQUEST = 'ADMIN_USER_INDEX_EXPAND_REQUEST';
|
||||||
const ADMIN_USER_INDEX_EXPAND_SUCCESS = 'ADMIN_USER_INDEX_EXPAND_SUCCESS';
|
const ADMIN_USER_INDEX_EXPAND_SUCCESS = 'ADMIN_USER_INDEX_EXPAND_SUCCESS';
|
||||||
|
@ -563,32 +555,6 @@ const setRole = (accountId: string, role: 'user' | 'moderator' | 'admin') =>
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const suggestUsers = (accountIds: string[]) =>
|
|
||||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
|
||||||
const nicknames = nicknamesFromIds(getState, accountIds);
|
|
||||||
dispatch({ type: ADMIN_USERS_SUGGEST_REQUEST, accountIds });
|
|
||||||
return api(getState)
|
|
||||||
.patch('/api/v1/pleroma/admin/users/suggest', { nicknames })
|
|
||||||
.then(({ data: { users } }) => {
|
|
||||||
dispatch({ type: ADMIN_USERS_SUGGEST_SUCCESS, users, accountIds });
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch({ type: ADMIN_USERS_SUGGEST_FAIL, error, accountIds });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const unsuggestUsers = (accountIds: string[]) =>
|
|
||||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
|
||||||
const nicknames = nicknamesFromIds(getState, accountIds);
|
|
||||||
dispatch({ type: ADMIN_USERS_UNSUGGEST_REQUEST, accountIds });
|
|
||||||
return api(getState)
|
|
||||||
.patch('/api/v1/pleroma/admin/users/unsuggest', { nicknames })
|
|
||||||
.then(({ data: { users } }) => {
|
|
||||||
dispatch({ type: ADMIN_USERS_UNSUGGEST_SUCCESS, users, accountIds });
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch({ type: ADMIN_USERS_UNSUGGEST_FAIL, error, accountIds });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const setUserIndexQuery = (query: string) => ({ type: ADMIN_USER_INDEX_QUERY_SET, query });
|
const setUserIndexQuery = (query: string) => ({ type: ADMIN_USER_INDEX_QUERY_SET, query });
|
||||||
|
|
||||||
const fetchUserIndex = () =>
|
const fetchUserIndex = () =>
|
||||||
|
@ -766,12 +732,6 @@ export {
|
||||||
ADMIN_REMOVE_PERMISSION_GROUP_REQUEST,
|
ADMIN_REMOVE_PERMISSION_GROUP_REQUEST,
|
||||||
ADMIN_REMOVE_PERMISSION_GROUP_SUCCESS,
|
ADMIN_REMOVE_PERMISSION_GROUP_SUCCESS,
|
||||||
ADMIN_REMOVE_PERMISSION_GROUP_FAIL,
|
ADMIN_REMOVE_PERMISSION_GROUP_FAIL,
|
||||||
ADMIN_USERS_SUGGEST_REQUEST,
|
|
||||||
ADMIN_USERS_SUGGEST_SUCCESS,
|
|
||||||
ADMIN_USERS_SUGGEST_FAIL,
|
|
||||||
ADMIN_USERS_UNSUGGEST_REQUEST,
|
|
||||||
ADMIN_USERS_UNSUGGEST_SUCCESS,
|
|
||||||
ADMIN_USERS_UNSUGGEST_FAIL,
|
|
||||||
ADMIN_USER_INDEX_EXPAND_FAIL,
|
ADMIN_USER_INDEX_EXPAND_FAIL,
|
||||||
ADMIN_USER_INDEX_EXPAND_REQUEST,
|
ADMIN_USER_INDEX_EXPAND_REQUEST,
|
||||||
ADMIN_USER_INDEX_EXPAND_SUCCESS,
|
ADMIN_USER_INDEX_EXPAND_SUCCESS,
|
||||||
|
@ -820,8 +780,6 @@ export {
|
||||||
promoteToModerator,
|
promoteToModerator,
|
||||||
demoteToUser,
|
demoteToUser,
|
||||||
setRole,
|
setRole,
|
||||||
suggestUsers,
|
|
||||||
unsuggestUsers,
|
|
||||||
setUserIndexQuery,
|
setUserIndexQuery,
|
||||||
fetchUserIndex,
|
fetchUserIndex,
|
||||||
expandUserIndex,
|
expandUserIndex,
|
||||||
|
|
71
app/soapbox/api/hooks/admin/useSuggest.ts
Normal file
71
app/soapbox/api/hooks/admin/useSuggest.ts
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
import { Entities } from 'soapbox/entity-store/entities';
|
||||||
|
import { useTransaction } from 'soapbox/entity-store/hooks';
|
||||||
|
import { EntityCallbacks } from 'soapbox/entity-store/hooks/types';
|
||||||
|
import { findEntity } from 'soapbox/entity-store/selectors';
|
||||||
|
import { useApi, useGetState } from 'soapbox/hooks';
|
||||||
|
|
||||||
|
import type { Account } from 'soapbox/schemas';
|
||||||
|
import type { RootState } from 'soapbox/store';
|
||||||
|
|
||||||
|
function useSuggest() {
|
||||||
|
const api = useApi();
|
||||||
|
const getState = useGetState();
|
||||||
|
const { transaction } = useTransaction();
|
||||||
|
|
||||||
|
function suggestEffect(accts: string[], suggested: boolean) {
|
||||||
|
const ids = selectIdsForAccts(getState(), accts);
|
||||||
|
|
||||||
|
const updater = (account: Account): Account => {
|
||||||
|
if (account.pleroma) {
|
||||||
|
account.pleroma.is_suggested = suggested;
|
||||||
|
}
|
||||||
|
return account;
|
||||||
|
};
|
||||||
|
|
||||||
|
transaction({
|
||||||
|
Accounts: ids.reduce<Record<string, (account: Account) => Account>>(
|
||||||
|
(result, id) => ({ ...result, [id]: updater }),
|
||||||
|
{}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function suggest(accts: string[], callbacks?: EntityCallbacks<void, unknown>) {
|
||||||
|
suggestEffect(accts, true);
|
||||||
|
try {
|
||||||
|
await api.patch('/api/v1/pleroma/admin/users/suggest', { nicknames: accts });
|
||||||
|
callbacks?.onSuccess?.();
|
||||||
|
} catch (e) {
|
||||||
|
callbacks?.onError?.(e);
|
||||||
|
suggestEffect(accts, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function unsuggest(accts: string[], callbacks?: EntityCallbacks<void, unknown>) {
|
||||||
|
suggestEffect(accts, false);
|
||||||
|
try {
|
||||||
|
await api.patch('/api/v1/pleroma/admin/users/unsuggest', { nicknames: accts });
|
||||||
|
callbacks?.onSuccess?.();
|
||||||
|
} catch (e) {
|
||||||
|
callbacks?.onError?.(e);
|
||||||
|
suggestEffect(accts, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
suggest,
|
||||||
|
unsuggest,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectIdsForAccts(state: RootState, accts: string[]): string[] {
|
||||||
|
return accts.map((acct) => {
|
||||||
|
const account = findEntity<Account>(
|
||||||
|
state,
|
||||||
|
Entities.ACCOUNTS,
|
||||||
|
(account) => account.acct === acct,
|
||||||
|
);
|
||||||
|
return account!.id;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export { useSuggest };
|
|
@ -3,9 +3,9 @@ import { useEffect, useState } from 'react';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { useAppDispatch, useAppSelector, useLoading } from 'soapbox/hooks';
|
import { useAppDispatch, useAppSelector, useLoading } from 'soapbox/hooks';
|
||||||
import { type RootState } from 'soapbox/store';
|
|
||||||
|
|
||||||
import { importEntities } from '../actions';
|
import { importEntities } from '../actions';
|
||||||
|
import { findEntity } from '../selectors';
|
||||||
import { Entity } from '../types';
|
import { Entity } from '../types';
|
||||||
|
|
||||||
import { EntityFn } from './types';
|
import { EntityFn } from './types';
|
||||||
|
@ -58,16 +58,4 @@ function useEntityLookup<TEntity extends Entity>(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function findEntity<TEntity extends Entity>(
|
|
||||||
state: RootState,
|
|
||||||
entityType: string,
|
|
||||||
lookupFn: LookupFn<TEntity>,
|
|
||||||
) {
|
|
||||||
const cache = state.entities[entityType];
|
|
||||||
|
|
||||||
if (cache) {
|
|
||||||
return (Object.values(cache.store) as TEntity[]).find(lookupFn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export { useEntityLookup };
|
export { useEntityLookup };
|
|
@ -44,10 +44,24 @@ function selectEntities<TEntity extends Entity>(state: RootState, path: Entities
|
||||||
) : [];
|
) : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Find an entity using a finder function. */
|
||||||
|
function findEntity<TEntity extends Entity>(
|
||||||
|
state: RootState,
|
||||||
|
entityType: string,
|
||||||
|
lookupFn: (entity: TEntity) => boolean,
|
||||||
|
) {
|
||||||
|
const cache = state.entities[entityType];
|
||||||
|
|
||||||
|
if (cache) {
|
||||||
|
return (Object.values(cache.store) as TEntity[]).find(lookupFn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
selectCache,
|
selectCache,
|
||||||
selectList,
|
selectList,
|
||||||
selectListState,
|
selectListState,
|
||||||
useListState,
|
useListState,
|
||||||
selectEntities,
|
selectEntities,
|
||||||
|
findEntity,
|
||||||
};
|
};
|
|
@ -4,12 +4,11 @@ import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||||
import {
|
import {
|
||||||
verifyUser,
|
verifyUser,
|
||||||
unverifyUser,
|
unverifyUser,
|
||||||
suggestUsers,
|
|
||||||
unsuggestUsers,
|
|
||||||
setBadges as saveBadges,
|
setBadges as saveBadges,
|
||||||
} from 'soapbox/actions/admin';
|
} from 'soapbox/actions/admin';
|
||||||
import { deactivateUserModal, deleteUserModal } from 'soapbox/actions/moderation';
|
import { deactivateUserModal, deleteUserModal } from 'soapbox/actions/moderation';
|
||||||
import { useAccount } from 'soapbox/api/hooks';
|
import { useAccount } from 'soapbox/api/hooks';
|
||||||
|
import { useSuggest } from 'soapbox/api/hooks/admin/useSuggest';
|
||||||
import Account from 'soapbox/components/account';
|
import Account from 'soapbox/components/account';
|
||||||
import List, { ListItem } from 'soapbox/components/list';
|
import List, { ListItem } from 'soapbox/components/list';
|
||||||
import MissingIndicator from 'soapbox/components/missing-indicator';
|
import MissingIndicator from 'soapbox/components/missing-indicator';
|
||||||
|
@ -45,6 +44,7 @@ const AccountModerationModal: React.FC<IAccountModerationModal> = ({ onClose, ac
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
|
const { suggest, unsuggest } = useSuggest();
|
||||||
const { account: ownAccount } = useOwnAccount();
|
const { account: ownAccount } = useOwnAccount();
|
||||||
const features = useFeatures();
|
const features = useFeatures();
|
||||||
const { account } = useAccount(accountId);
|
const { account } = useAccount(accountId);
|
||||||
|
@ -81,11 +81,11 @@ const AccountModerationModal: React.FC<IAccountModerationModal> = ({ onClose, ac
|
||||||
const { checked } = e.target;
|
const { checked } = e.target;
|
||||||
|
|
||||||
const message = checked ? messages.userSuggested : messages.userUnsuggested;
|
const message = checked ? messages.userSuggested : messages.userUnsuggested;
|
||||||
const action = checked ? suggestUsers : unsuggestUsers;
|
const action = checked ? suggest : unsuggest;
|
||||||
|
|
||||||
dispatch(action([account.id]))
|
action([account.acct], {
|
||||||
.then(() => toast.success(intl.formatMessage(message, { acct: account.acct })))
|
onSuccess: () => toast.success(intl.formatMessage(message, { acct: account.acct })),
|
||||||
.catch(() => {});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeactivate = () => {
|
const handleDeactivate = () => {
|
||||||
|
|
|
@ -23,10 +23,6 @@ import {
|
||||||
ADMIN_USERS_DELETE_FAIL,
|
ADMIN_USERS_DELETE_FAIL,
|
||||||
ADMIN_USERS_DEACTIVATE_REQUEST,
|
ADMIN_USERS_DEACTIVATE_REQUEST,
|
||||||
ADMIN_USERS_DEACTIVATE_FAIL,
|
ADMIN_USERS_DEACTIVATE_FAIL,
|
||||||
ADMIN_USERS_SUGGEST_REQUEST,
|
|
||||||
ADMIN_USERS_SUGGEST_FAIL,
|
|
||||||
ADMIN_USERS_UNSUGGEST_REQUEST,
|
|
||||||
ADMIN_USERS_UNSUGGEST_FAIL,
|
|
||||||
} from 'soapbox/actions/admin';
|
} from 'soapbox/actions/admin';
|
||||||
import { CHATS_FETCH_SUCCESS, CHATS_EXPAND_SUCCESS, CHAT_FETCH_SUCCESS } from 'soapbox/actions/chats';
|
import { CHATS_FETCH_SUCCESS, CHATS_EXPAND_SUCCESS, CHAT_FETCH_SUCCESS } from 'soapbox/actions/chats';
|
||||||
import {
|
import {
|
||||||
|
@ -234,14 +230,6 @@ const importAdminUsers = (state: State, adminUsers: Array<Record<string, any>>):
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const setSuggested = (state: State, accountIds: Array<string>, isSuggested: boolean): State => {
|
|
||||||
return state.withMutations(state => {
|
|
||||||
accountIds.forEach(id => {
|
|
||||||
state.setIn([id, 'pleroma', 'is_suggested'], isSuggested);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function accounts(state: State = initialState, action: AnyAction): State {
|
export default function accounts(state: State = initialState, action: AnyAction): State {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case ACCOUNT_IMPORT:
|
case ACCOUNT_IMPORT:
|
||||||
|
@ -280,12 +268,6 @@ export default function accounts(state: State = initialState, action: AnyAction)
|
||||||
return setActive(state, action.accountIds, true);
|
return setActive(state, action.accountIds, true);
|
||||||
case ADMIN_USERS_FETCH_SUCCESS:
|
case ADMIN_USERS_FETCH_SUCCESS:
|
||||||
return importAdminUsers(state, action.users);
|
return importAdminUsers(state, action.users);
|
||||||
case ADMIN_USERS_SUGGEST_REQUEST:
|
|
||||||
case ADMIN_USERS_UNSUGGEST_FAIL:
|
|
||||||
return setSuggested(state, action.accountIds, true);
|
|
||||||
case ADMIN_USERS_UNSUGGEST_REQUEST:
|
|
||||||
case ADMIN_USERS_SUGGEST_FAIL:
|
|
||||||
return setSuggested(state, action.accountIds, false);
|
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue