diff --git a/lib/hooks/thread-hooks.js b/lib/hooks/thread-hooks.js --- a/lib/hooks/thread-hooks.js +++ b/lib/hooks/thread-hooks.js @@ -306,7 +306,7 @@ } export type ChangeThreadMemberRolesInput = { - +threadID: string, + +threadInfo: ThreadInfo, +memberIDs: $ReadOnlyArray, +newRole: string, }; @@ -320,8 +320,9 @@ input: ChangeThreadMemberRolesInput, ) => Promise) => async input => { - const { threadID, memberIDs, newRole } = input; - const keyserverID = extractKeyserverIDFromID(input.threadID); + const { threadInfo, memberIDs, newRole } = input; + const threadID = threadInfo.id; + const keyserverID = extractKeyserverIDFromID(threadID); const requests = { [keyserverID]: { threadID, @@ -346,7 +347,31 @@ function useChangeThreadMemberRoles(): ( input: ChangeThreadMemberRolesInput, ) => Promise { - return useKeyserverCall(changeThreadMemberRoles); + const keyserverCall = useKeyserverCall(changeThreadMemberRoles); + const dispatchActionPromise = useDispatchActionPromise(); + return React.useCallback( + async (input: ChangeThreadMemberRolesInput) => { + const { threadInfo, memberIDs, newRole } = input; + const protocol = threadSpecs[threadInfo.type].protocol(); + invariant( + protocol.changeThreadMemberRoles, + `changeThreadMemberRoles not supported for thread type ` + + `${threadInfo.type}`, + ); + return protocol.changeThreadMemberRoles( + { + threadInfo, + memberIDs, + newRole, + }, + { + keyserverCall, + dispatchActionPromise, + }, + ); + }, + [dispatchActionPromise, keyserverCall], + ); } const newThinThread = diff --git a/lib/shared/threads/protocols/keyserver-thread-protocol.js b/lib/shared/threads/protocols/keyserver-thread-protocol.js --- a/lib/shared/threads/protocols/keyserver-thread-protocol.js +++ b/lib/shared/threads/protocols/keyserver-thread-protocol.js @@ -12,6 +12,7 @@ sendReactionMessageActionTypes, } from '../../../actions/message-actions.js'; import { + changeThreadMemberRolesActionTypes, changeThreadSettingsActionTypes, leaveThreadActionTypes, newThreadActionTypes, @@ -116,6 +117,8 @@ ProtocolDeleteMessageInput, JoinThreadUtils, ProtocolJoinThreadInput, + ProtocolChangeThreadMemberRolesInput, + ChangeThreadMemberRolesUtils, } from '../thread-spec.js'; import { threadTypeIsSidebar } from '../thread-specs.js'; @@ -373,6 +376,26 @@ await addMembersPromise; }, + changeThreadMemberRoles: async ( + input: ProtocolChangeThreadMemberRolesInput, + utils: ChangeThreadMemberRolesUtils, + ) => { + const { threadInfo, memberIDs, newRole } = input; + + const promise = utils.keyserverCall({ + threadInfo, + memberIDs, + newRole, + }); + + void utils.dispatchActionPromise( + changeThreadMemberRolesActionTypes, + promise, + ); + + return await promise; + }, + updateSubscription: ( protocolInput: ProtocolUpdateSubscriptionInput, utils: UpdateSubscriptionUtils, diff --git a/lib/shared/threads/thread-spec.js b/lib/shared/threads/thread-spec.js --- a/lib/shared/threads/thread-spec.js +++ b/lib/shared/threads/thread-spec.js @@ -238,6 +238,16 @@ +dispatchActionPromise: DispatchActionPromise, }; +export type ProtocolChangeThreadMemberRolesInput = { + +threadInfo: ThreadInfo, + +memberIDs: $ReadOnlyArray, + +newRole: string, +}; +export type ChangeThreadMemberRolesUtils = { + +keyserverCall: ProtocolChangeThreadMemberRolesInput => Promise, + +dispatchActionPromise: DispatchActionPromise, +}; + export type ProtocolUpdateSubscriptionInput = { +input: UseUpdateSubscriptionInput, +viewerID: ?string, @@ -374,6 +384,10 @@ input: ProtocolAddThreadMembersInput, utils: AddThreadMembersUtils, ) => Promise, + +changeThreadMemberRoles?: ( + input: ProtocolChangeThreadMemberRolesInput, + utils: ChangeThreadMemberRolesUtils, + ) => Promise, +updateSubscription: ( input: ProtocolUpdateSubscriptionInput, utils: UpdateSubscriptionUtils, diff --git a/native/roles/change-roles-header-right-button.react.js b/native/roles/change-roles-header-right-button.react.js --- a/native/roles/change-roles-header-right-button.react.js +++ b/native/roles/change-roles-header-right-button.react.js @@ -6,9 +6,7 @@ import { Text, View } from 'react-native'; import { TouchableOpacity } from 'react-native-gesture-handler'; -import { changeThreadMemberRolesActionTypes } from 'lib/actions/thread-action-types.js'; import { useChangeThreadMemberRoles } from 'lib/hooks/thread-hooks.js'; -import { useDispatchActionPromise } from 'lib/utils/redux-promise-utils.js'; import type { NavigationRoute } from '../navigation/route-names'; import { useColors } from '../themes/colors.js'; @@ -26,8 +24,7 @@ invariant(selectedRole, 'Expected selected role to be defined'); const navigation = useNavigation(); - const callChangeThreadMemberRoles = useChangeThreadMemberRoles(); - const dispatchActionPromise = useDispatchActionPromise(); + const changeThreadMemberRoles = useChangeThreadMemberRoles(); const { disabledButton, purpleLink } = useColors(); const textStyle = React.useMemo( @@ -44,24 +41,20 @@ return; } - void dispatchActionPromise( - changeThreadMemberRolesActionTypes, - callChangeThreadMemberRoles({ - threadID: threadInfo.id, - memberIDs: [memberInfo.id], - newRole: selectedRole, - }), - ); + void changeThreadMemberRoles({ + threadInfo, + memberIDs: [memberInfo.id], + newRole: selectedRole, + }); navigation.goBack(); }, [ - callChangeThreadMemberRoles, - dispatchActionPromise, + changeThreadMemberRoles, initialRole, memberInfo.id, navigation, selectedRole, - threadInfo.id, + threadInfo, ]); const saveButton = React.useMemo(() => { diff --git a/web/modals/threads/members/change-member-role-modal.react.js b/web/modals/threads/members/change-member-role-modal.react.js --- a/web/modals/threads/members/change-member-role-modal.react.js +++ b/web/modals/threads/members/change-member-role-modal.react.js @@ -3,7 +3,6 @@ import invariant from 'invariant'; import * as React from 'react'; -import { changeThreadMemberRolesActionTypes } from 'lib/actions/thread-action-types.js'; import { useModalContext } from 'lib/components/modal-provider.react.js'; import SWMansionIcon from 'lib/components/swmansion-icon.react.js'; import { useChangeThreadMemberRoles } from 'lib/hooks/thread-hooks.js'; @@ -14,7 +13,6 @@ ThreadInfo, } from 'lib/types/minimally-encoded-thread-permissions-types.js'; import { values } from 'lib/utils/objects.js'; -import { useDispatchActionPromise } from 'lib/utils/redux-promise-utils.js'; import css from './change-member-role-modal.css'; import UserAvatar from '../../../avatars/user-avatar.react.js'; @@ -32,8 +30,7 @@ function ChangeMemberRoleModal(props: ChangeMemberRoleModalProps): React.Node { const { memberInfo, threadInfo } = props; const { pushModal, popModal } = useModalContext(); - const dispatchActionPromise = useDispatchActionPromise(); - const callChangeThreadMemberRoles = useChangeThreadMemberRoles(); + const changeThreadMemberRoles = useChangeThreadMemberRoles(); const otherUsersButNoOtherAdminsValue = useSelector( otherUsersButNoOtherAdmins(threadInfo.id), ); @@ -86,26 +83,20 @@ return; } - const createChangeThreadMemberRolesPromise = () => - callChangeThreadMemberRoles({ - threadID: threadInfo.id, - memberIDs: [memberInfo.id], - newRole: selectedRole, - }); + void changeThreadMemberRoles({ + threadInfo, + memberIDs: [memberInfo.id], + newRole: selectedRole, + }); - void dispatchActionPromise( - changeThreadMemberRolesActionTypes, - createChangeThreadMemberRolesPromise(), - ); popModal(); }, [ - callChangeThreadMemberRoles, - dispatchActionPromise, + changeThreadMemberRoles, initialSelectedRole, memberInfo.id, popModal, selectedRole, - threadInfo.id, + threadInfo, ]); const primaryButton = React.useMemo(