diff --git a/lib/actions/thread-actions.js b/lib/actions/thread-actions.js --- a/lib/actions/thread-actions.js +++ b/lib/actions/thread-actions.js @@ -1,508 +1,67 @@ // @flow -import invariant from 'invariant'; -import * as React from 'react'; -import uuid from 'uuid'; - -import genesis from '../facts/genesis.js'; -import { extractKeyserverIDFromID } from '../keyserver-conn/keyserver-call-utils.js'; -import { useKeyserverCall } from '../keyserver-conn/keyserver-call.js'; -import type { CallKeyserverEndpoint } from '../keyserver-conn/keyserver-conn-types.js'; -import { - type OutboundDMOperationSpecification, - dmOperationSpecificationTypes, -} from '../shared/dm-ops/dm-op-types.js'; -import { getCreateThickRawThreadInfoInputFromThreadInfo } from '../shared/dm-ops/dm-op-utils.js'; -import { useProcessAndSendDMOperation } from '../shared/dm-ops/process-dm-ops.js'; -import { threadSpecs } from '../shared/threads/thread-specs.js'; -import { permissionsAndAuthRelatedRequestTimeout } from '../shared/timeouts.js'; -import type { DMJoinThreadOperation } from '../types/dm-ops.js'; -import type { - ThreadInfo, - RawThreadInfo, -} from '../types/minimally-encoded-thread-permissions-types.js'; -import { thickThreadTypes } from '../types/thread-types-enum.js'; -import type { - ChangeThreadSettingsPayload, - LeaveThreadPayload, - UpdateThreadRequest, - ClientNewThinThreadRequest, - NewThreadResult, - ClientThreadJoinRequest, - ThreadJoinPayload, - ThreadFetchMediaRequest, - ThreadFetchMediaResult, - RoleModificationRequest, - RoleModificationPayload, - RoleDeletionRequest, - RoleDeletionPayload, -} from '../types/thread-types.js'; -import { values } from '../utils/objects.js'; -import { useSelector } from '../utils/redux-utils.js'; - -export type DeleteThreadInput = { - +threadID: string, -}; - const deleteThreadActionTypes = Object.freeze({ started: 'DELETE_THREAD_STARTED', success: 'DELETE_THREAD_SUCCESS', failed: 'DELETE_THREAD_FAILED', }); -const deleteThreadEndpointOptions = { - timeout: permissionsAndAuthRelatedRequestTimeout, -}; - -const deleteThread = - ( - callKeyserverEndpoint: CallKeyserverEndpoint, - ): ((input: DeleteThreadInput) => Promise) => - async input => { - const keyserverID = extractKeyserverIDFromID(input.threadID); - const requests = { [keyserverID]: input }; - - const responses = await callKeyserverEndpoint( - 'delete_thread', - requests, - deleteThreadEndpointOptions, - ); - const response = responses[keyserverID]; - return { - updatesResult: response.updatesResult, - }; - }; - -function useDeleteThread(): ( - input: DeleteThreadInput, -) => Promise { - return useKeyserverCall(deleteThread); -} const changeThreadSettingsActionTypes = Object.freeze({ started: 'CHANGE_THREAD_SETTINGS_STARTED', success: 'CHANGE_THREAD_SETTINGS_SUCCESS', failed: 'CHANGE_THREAD_SETTINGS_FAILED', }); -const changeThreadSettingsEndpointOptions = { - timeout: permissionsAndAuthRelatedRequestTimeout, -}; - -const changeThreadSettings = - ( - callKeyserverEndpoint: CallKeyserverEndpoint, - ): ((input: UpdateThreadRequest) => Promise) => - async input => { - invariant( - Object.keys(input.changes).length > 0, - 'No changes provided to changeThreadSettings!', - ); - const keyserverID = extractKeyserverIDFromID(input.threadID); - const requests = { [keyserverID]: input }; - - const responses = await callKeyserverEndpoint( - 'update_thread', - requests, - changeThreadSettingsEndpointOptions, - ); - const response = responses[keyserverID]; - return { - threadID: input.threadID, - updatesResult: response.updatesResult, - newMessageInfos: response.newMessageInfos, - }; - }; - -export type UseChangeThreadSettingsInput = $ReadOnly<{ - ...UpdateThreadRequest, - +threadInfo: ThreadInfo, -}>; - -function useChangeThreadSettings(): ( - input: UseChangeThreadSettingsInput, -) => Promise { - const processAndSendDMOperation = useProcessAndSendDMOperation(); - const viewerID = useSelector( - state => state.currentUserInfo && state.currentUserInfo.id, - ); - - const keyserverCall = useKeyserverCall(changeThreadSettings); - - return React.useCallback( - async (input: UseChangeThreadSettingsInput) => - threadSpecs[input.threadInfo.type].protocol.changeThreadSettings( - { input, viewerID }, - { - processAndSendDMOperation, - keyserverChangeThreadSettings: keyserverCall, - }, - ), - [keyserverCall, processAndSendDMOperation, viewerID], - ); -} - -export type RemoveUsersFromThreadInput = { - +threadID: string, - +memberIDs: $ReadOnlyArray, -}; - const removeUsersFromThreadActionTypes = Object.freeze({ started: 'REMOVE_USERS_FROM_THREAD_STARTED', success: 'REMOVE_USERS_FROM_THREAD_SUCCESS', failed: 'REMOVE_USERS_FROM_THREAD_FAILED', }); -const removeMembersFromThreadEndpointOptions = { - timeout: permissionsAndAuthRelatedRequestTimeout, -}; - -const removeUsersFromThread = - ( - callKeyserverEndpoint: CallKeyserverEndpoint, - ): (( - input: RemoveUsersFromThreadInput, - ) => Promise) => - async input => { - const keyserverID = extractKeyserverIDFromID(input.threadID); - const requests = { [keyserverID]: input }; - - const responses = await callKeyserverEndpoint( - 'remove_members', - requests, - removeMembersFromThreadEndpointOptions, - ); - const response = responses[keyserverID]; - return { - threadID: input.threadID, - updatesResult: response.updatesResult, - newMessageInfos: response.newMessageInfos, - }; - }; - -function useRemoveUsersFromThread(): ( - input: RemoveUsersFromThreadInput, -) => Promise { - return useKeyserverCall(removeUsersFromThread); -} - -export type ChangeThreadMemberRolesInput = { - +threadID: string, - +memberIDs: $ReadOnlyArray, - +newRole: string, -}; - const changeThreadMemberRolesActionTypes = Object.freeze({ started: 'CHANGE_THREAD_MEMBER_ROLES_STARTED', success: 'CHANGE_THREAD_MEMBER_ROLES_SUCCESS', failed: 'CHANGE_THREAD_MEMBER_ROLES_FAILED', }); -const changeThreadMemberRoleEndpointOptions = { - timeout: permissionsAndAuthRelatedRequestTimeout, -}; - -const changeThreadMemberRoles = - ( - callKeyserverEndpoint: CallKeyserverEndpoint, - ): (( - input: ChangeThreadMemberRolesInput, - ) => Promise) => - async input => { - const { threadID, memberIDs, newRole } = input; - const keyserverID = extractKeyserverIDFromID(input.threadID); - const requests = { - [keyserverID]: { - threadID, - memberIDs, - role: newRole, - }, - }; - - const responses = await callKeyserverEndpoint( - 'update_role', - requests, - changeThreadMemberRoleEndpointOptions, - ); - const response = responses[keyserverID]; - return { - threadID, - updatesResult: response.updatesResult, - newMessageInfos: response.newMessageInfos, - }; - }; - -function useChangeThreadMemberRoles(): ( - input: ChangeThreadMemberRolesInput, -) => Promise { - return useKeyserverCall(changeThreadMemberRoles); -} - const newThreadActionTypes = Object.freeze({ started: 'NEW_THREAD_STARTED', success: 'NEW_THREAD_SUCCESS', failed: 'NEW_THREAD_FAILED', }); -const newThinThread = - ( - callKeyserverEndpoint: CallKeyserverEndpoint, - ): ((input: ClientNewThinThreadRequest) => Promise) => - async input => { - const parentThreadID = input.parentThreadID ?? genesis().id; - const keyserverID = extractKeyserverIDFromID(parentThreadID); - const requests = { [keyserverID]: input }; - - const responses = await callKeyserverEndpoint('create_thread', requests); - const response = responses[keyserverID]; - - return { - newThreadID: response.newThreadID, - updatesResult: response.updatesResult, - newMessageInfos: response.newMessageInfos, - userInfos: response.userInfos, - }; - }; - -function useNewThinThread(): ( - input: ClientNewThinThreadRequest, -) => Promise { - return useKeyserverCall(newThinThread); -} const joinThreadActionTypes = Object.freeze({ started: 'JOIN_THREAD_STARTED', success: 'JOIN_THREAD_SUCCESS', failed: 'JOIN_THREAD_FAILED', }); -const joinThreadOptions = { - timeout: permissionsAndAuthRelatedRequestTimeout, -}; -const joinThread = - ( - callKeyserverEndpoint: CallKeyserverEndpoint, - ): ((input: ClientThreadJoinRequest) => Promise) => - async input => { - const keyserverID = extractKeyserverIDFromID(input.threadID); - const requests = { [keyserverID]: input }; - - const responses = await callKeyserverEndpoint( - 'join_thread', - requests, - joinThreadOptions, - ); - const response = responses[keyserverID]; - const userInfos = values(response.userInfos); - return { - updatesResult: response.updatesResult, - rawMessageInfos: response.rawMessageInfos, - truncationStatuses: response.truncationStatuses, - userInfos, - keyserverID, - }; - }; - -export type UseJoinThreadInput = $ReadOnly< - | { - +thick: false, - ...ClientThreadJoinRequest, - } - | { - +thick: true, - +rawThreadInfo: RawThreadInfo, - }, ->; - -function useJoinThread(): ( - input: UseJoinThreadInput, -) => Promise { - const processAndSendDMOperation = useProcessAndSendDMOperation(); - const viewerID = useSelector( - state => state.currentUserInfo && state.currentUserInfo.id, - ); - const keyserverCall = useKeyserverCall(joinThread); - return React.useCallback( - async (input: UseJoinThreadInput) => { - if (!input.thick) { - const { thick, ...rest } = input; - return await keyserverCall({ ...rest }); - } - - const { rawThreadInfo } = input; - - invariant(viewerID, 'viewerID should be set'); - invariant(rawThreadInfo.thick, 'thread must be thick'); - - const existingThreadDetails = - getCreateThickRawThreadInfoInputFromThreadInfo(rawThreadInfo); - - const op: DMJoinThreadOperation = { - type: 'join_thread', - joinerID: viewerID, - time: Date.now(), - messageID: uuid.v4(), - existingThreadDetails, - }; - const opSpecification: OutboundDMOperationSpecification = { - type: dmOperationSpecificationTypes.OUTBOUND, - op, - recipients: { - type: 'all_thread_members', - threadID: - rawThreadInfo.type === thickThreadTypes.THICK_SIDEBAR && - rawThreadInfo.parentThreadID - ? rawThreadInfo.parentThreadID - : rawThreadInfo.id, - }, - }; - - await processAndSendDMOperation(opSpecification); - return ({ - updatesResult: { newUpdates: [] }, - rawMessageInfos: [], - truncationStatuses: {}, - userInfos: [], - }: ThreadJoinPayload); - }, - [keyserverCall, processAndSendDMOperation, viewerID], - ); -} - -export type LeaveThreadInput = { - +threadID: string, -}; const leaveThreadActionTypes = Object.freeze({ started: 'LEAVE_THREAD_STARTED', success: 'LEAVE_THREAD_SUCCESS', failed: 'LEAVE_THREAD_FAILED', }); -const leaveThreadEndpointOptions = { - timeout: permissionsAndAuthRelatedRequestTimeout, -}; -const leaveThread = - ( - callKeyserverEndpoint: CallKeyserverEndpoint, - ): ((input: LeaveThreadInput) => Promise) => - async input => { - const keyserverID = extractKeyserverIDFromID(input.threadID); - const requests = { [keyserverID]: input }; - - const responses = await callKeyserverEndpoint( - 'leave_thread', - requests, - leaveThreadEndpointOptions, - ); - const response = responses[keyserverID]; - return { - updatesResult: response.updatesResult, - }; - }; - -function useLeaveThread(): ( - input: LeaveThreadInput, -) => Promise { - return useKeyserverCall(leaveThread); -} - -const fetchThreadMedia = - ( - callKeyserverEndpoint: CallKeyserverEndpoint, - ): ((input: ThreadFetchMediaRequest) => Promise) => - async input => { - const keyserverID = extractKeyserverIDFromID(input.threadID); - const requests = { [keyserverID]: input }; - - const responses = await callKeyserverEndpoint( - 'fetch_thread_media', - requests, - ); - const response = responses[keyserverID]; - return { media: response.media }; - }; - -function useFetchThreadMedia(): ( - input: ThreadFetchMediaRequest, -) => Promise { - return useKeyserverCall(fetchThreadMedia); -} const modifyCommunityRoleActionTypes = Object.freeze({ started: 'MODIFY_COMMUNITY_ROLE_STARTED', success: 'MODIFY_COMMUNITY_ROLE_SUCCESS', failed: 'MODIFY_COMMUNITY_ROLE_FAILED', }); -const modifyCommunityRole = - ( - callKeyserverEndpoint: CallKeyserverEndpoint, - ): ((input: RoleModificationRequest) => Promise) => - async input => { - const keyserverID = extractKeyserverIDFromID(input.community); - const requests = { [keyserverID]: input }; - - const responses = await callKeyserverEndpoint( - 'modify_community_role', - requests, - ); - const response = responses[keyserverID]; - return { - threadInfo: response.threadInfo, - updatesResult: response.updatesResult, - }; - }; - -function useModifyCommunityRole(): ( - input: RoleModificationRequest, -) => Promise { - return useKeyserverCall(modifyCommunityRole); -} const deleteCommunityRoleActionTypes = Object.freeze({ started: 'DELETE_COMMUNITY_ROLE_STARTED', success: 'DELETE_COMMUNITY_ROLE_SUCCESS', failed: 'DELETE_COMMUNITY_ROLE_FAILED', }); -const deleteCommunityRole = - ( - callKeyserverEndpoint: CallKeyserverEndpoint, - ): ((input: RoleDeletionRequest) => Promise) => - async input => { - const keyserverID = extractKeyserverIDFromID(input.community); - const requests = { [keyserverID]: input }; - - const responses = await callKeyserverEndpoint( - 'delete_community_role', - requests, - ); - const response = responses[keyserverID]; - return { - threadInfo: response.threadInfo, - updatesResult: response.updatesResult, - }; - }; - -function useDeleteCommunityRole(): ( - input: RoleDeletionRequest, -) => Promise { - return useKeyserverCall(deleteCommunityRole); -} export { deleteThreadActionTypes, - useDeleteThread, changeThreadSettingsActionTypes, - useChangeThreadSettings, removeUsersFromThreadActionTypes, - useRemoveUsersFromThread, changeThreadMemberRolesActionTypes, - useChangeThreadMemberRoles, newThreadActionTypes, - useNewThinThread, joinThreadActionTypes, - useJoinThread, leaveThreadActionTypes, - useLeaveThread, - useFetchThreadMedia, modifyCommunityRoleActionTypes, - useModifyCommunityRole, deleteCommunityRoleActionTypes, - useDeleteCommunityRole, }; diff --git a/lib/components/base-edit-thread-avatar-provider.react.js b/lib/components/base-edit-thread-avatar-provider.react.js --- a/lib/components/base-edit-thread-avatar-provider.react.js +++ b/lib/components/base-edit-thread-avatar-provider.react.js @@ -2,10 +2,8 @@ import * as React from 'react'; -import { - useChangeThreadSettings, - changeThreadSettingsActionTypes, -} from '../actions/thread-actions.js'; +import { changeThreadSettingsActionTypes } from '../actions/thread-actions.js'; +import { useChangeThreadSettings } from '../hooks/thread-hooks.js'; import { createLoadingStatusSelector } from '../selectors/loading-selectors.js'; import { threadInfoSelector } from '../selectors/thread-selectors.js'; import type { UpdateUserAvatarRequest } from '../types/avatar-types.js'; diff --git a/lib/hooks/promote-sidebar.react.js b/lib/hooks/promote-sidebar.react.js --- a/lib/hooks/promote-sidebar.react.js +++ b/lib/hooks/promote-sidebar.react.js @@ -2,10 +2,8 @@ import * as React from 'react'; -import { - changeThreadSettingsActionTypes, - useChangeThreadSettings, -} from '../actions/thread-actions.js'; +import { useChangeThreadSettings } from './thread-hooks.js'; +import { changeThreadSettingsActionTypes } from '../actions/thread-actions.js'; import { createLoadingStatusSelector } from '../selectors/loading-selectors.js'; import { threadInfoSelector } from '../selectors/thread-selectors.js'; import { 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 @@ -1,24 +1,51 @@ // @flow import invariant from 'invariant'; -import * as React from 'react'; +import React from 'react'; import uuid from 'uuid'; import { useChatMentionContext } from './chat-mention-hooks.js'; import genesis from '../facts/genesis.js'; +import { extractKeyserverIDFromID } from '../keyserver-conn/keyserver-call-utils.js'; +import { useKeyserverCall } from '../keyserver-conn/keyserver-call.js'; +import type { CallKeyserverEndpoint } from '../keyserver-conn/keyserver-conn-types.js'; import { childThreadInfos } from '../selectors/thread-selectors.js'; import { type OutboundDMOperationSpecification, dmOperationSpecificationTypes, } from '../shared/dm-ops/dm-op-types.js'; +import { getCreateThickRawThreadInfoInputFromThreadInfo } from '../shared/dm-ops/dm-op-utils.js'; import { useProcessAndSendDMOperation } from '../shared/dm-ops/process-dm-ops.js'; +import { threadSpecs } from '../shared/threads/thread-specs.js'; +import { permissionsAndAuthRelatedRequestTimeout } from '../shared/timeouts.js'; import type { DMCreateSidebarOperation, DMCreateThreadOperation, + DMJoinThreadOperation, } from '../types/dm-ops'; -import type { ResolvedThreadInfo } from '../types/minimally-encoded-thread-permissions-types.js'; -import { threadTypes } from '../types/thread-types-enum.js'; -import type { NewThickThreadRequest } from '../types/thread-types.js'; +import type { + RawThreadInfo, + ResolvedThreadInfo, + ThreadInfo, +} from '../types/minimally-encoded-thread-permissions-types.js'; +import { thickThreadTypes, threadTypes } from '../types/thread-types-enum.js'; +import type { + ChangeThreadSettingsPayload, + ClientNewThinThreadRequest, + ClientThreadJoinRequest, + LeaveThreadPayload, + NewThickThreadRequest, + NewThreadResult, + RoleDeletionPayload, + RoleDeletionRequest, + RoleModificationPayload, + RoleModificationRequest, + ThreadFetchMediaRequest, + ThreadFetchMediaResult, + ThreadJoinPayload, + UpdateThreadRequest, +} from '../types/thread-types.js'; +import { values } from '../utils/objects.js'; import { useSelector } from '../utils/redux-utils.js'; function useChildThreadInfosMap(): { @@ -130,3 +157,403 @@ } export { useChildThreadInfosMap, useNewThickThread }; +export type DeleteThreadInput = { + +threadID: string, +}; +const deleteThreadEndpointOptions = { + timeout: permissionsAndAuthRelatedRequestTimeout, +}; +const deleteThread = + ( + callKeyserverEndpoint: CallKeyserverEndpoint, + ): ((input: DeleteThreadInput) => Promise) => + async input => { + const keyserverID = extractKeyserverIDFromID(input.threadID); + const requests = { [keyserverID]: input }; + + const responses = await callKeyserverEndpoint( + 'delete_thread', + requests, + deleteThreadEndpointOptions, + ); + const response = responses[keyserverID]; + return { + updatesResult: response.updatesResult, + }; + }; + +function useDeleteThread(): ( + input: DeleteThreadInput, +) => Promise { + return useKeyserverCall(deleteThread); +} + +const changeThreadSettingsEndpointOptions = { + timeout: permissionsAndAuthRelatedRequestTimeout, +}; +const changeThreadSettings = + ( + callKeyserverEndpoint: CallKeyserverEndpoint, + ): ((input: UpdateThreadRequest) => Promise) => + async input => { + invariant( + Object.keys(input.changes).length > 0, + 'No changes provided to changeThreadSettings!', + ); + const keyserverID = extractKeyserverIDFromID(input.threadID); + const requests = { [keyserverID]: input }; + + const responses = await callKeyserverEndpoint( + 'update_thread', + requests, + changeThreadSettingsEndpointOptions, + ); + const response = responses[keyserverID]; + return { + threadID: input.threadID, + updatesResult: response.updatesResult, + newMessageInfos: response.newMessageInfos, + }; + }; +export type UseChangeThreadSettingsInput = $ReadOnly<{ + ...UpdateThreadRequest, + +threadInfo: ThreadInfo, +}>; + +function useChangeThreadSettings(): ( + input: UseChangeThreadSettingsInput, +) => Promise { + const processAndSendDMOperation = useProcessAndSendDMOperation(); + const viewerID = useSelector( + state => state.currentUserInfo && state.currentUserInfo.id, + ); + + const keyserverCall = useKeyserverCall(changeThreadSettings); + + return React.useCallback( + async (input: UseChangeThreadSettingsInput) => + threadSpecs[input.threadInfo.type].protocol.changeThreadSettings( + { input, viewerID }, + { + processAndSendDMOperation, + keyserverChangeThreadSettings: keyserverCall, + }, + ), + [keyserverCall, processAndSendDMOperation, viewerID], + ); +} + +export type RemoveUsersFromThreadInput = { + +threadID: string, + +memberIDs: $ReadOnlyArray, +}; +const removeMembersFromThreadEndpointOptions = { + timeout: permissionsAndAuthRelatedRequestTimeout, +}; +const removeUsersFromThread = + ( + callKeyserverEndpoint: CallKeyserverEndpoint, + ): (( + input: RemoveUsersFromThreadInput, + ) => Promise) => + async input => { + const keyserverID = extractKeyserverIDFromID(input.threadID); + const requests = { [keyserverID]: input }; + + const responses = await callKeyserverEndpoint( + 'remove_members', + requests, + removeMembersFromThreadEndpointOptions, + ); + const response = responses[keyserverID]; + return { + threadID: input.threadID, + updatesResult: response.updatesResult, + newMessageInfos: response.newMessageInfos, + }; + }; + +function useRemoveUsersFromThread(): ( + input: RemoveUsersFromThreadInput, +) => Promise { + return useKeyserverCall(removeUsersFromThread); +} + +export type ChangeThreadMemberRolesInput = { + +threadID: string, + +memberIDs: $ReadOnlyArray, + +newRole: string, +}; +const changeThreadMemberRoleEndpointOptions = { + timeout: permissionsAndAuthRelatedRequestTimeout, +}; +const changeThreadMemberRoles = + ( + callKeyserverEndpoint: CallKeyserverEndpoint, + ): (( + input: ChangeThreadMemberRolesInput, + ) => Promise) => + async input => { + const { threadID, memberIDs, newRole } = input; + const keyserverID = extractKeyserverIDFromID(input.threadID); + const requests = { + [keyserverID]: { + threadID, + memberIDs, + role: newRole, + }, + }; + + const responses = await callKeyserverEndpoint( + 'update_role', + requests, + changeThreadMemberRoleEndpointOptions, + ); + const response = responses[keyserverID]; + return { + threadID, + updatesResult: response.updatesResult, + newMessageInfos: response.newMessageInfos, + }; + }; + +function useChangeThreadMemberRoles(): ( + input: ChangeThreadMemberRolesInput, +) => Promise { + return useKeyserverCall(changeThreadMemberRoles); +} + +const newThinThread = + ( + callKeyserverEndpoint: CallKeyserverEndpoint, + ): ((input: ClientNewThinThreadRequest) => Promise) => + async input => { + const parentThreadID = input.parentThreadID ?? genesis().id; + const keyserverID = extractKeyserverIDFromID(parentThreadID); + const requests = { [keyserverID]: input }; + + const responses = await callKeyserverEndpoint('create_thread', requests); + const response = responses[keyserverID]; + + return { + newThreadID: response.newThreadID, + updatesResult: response.updatesResult, + newMessageInfos: response.newMessageInfos, + userInfos: response.userInfos, + }; + }; + +function useNewThinThread(): ( + input: ClientNewThinThreadRequest, +) => Promise { + return useKeyserverCall(newThinThread); +} + +const joinThreadOptions = { + timeout: permissionsAndAuthRelatedRequestTimeout, +}; +const joinThread = + ( + callKeyserverEndpoint: CallKeyserverEndpoint, + ): ((input: ClientThreadJoinRequest) => Promise) => + async input => { + const keyserverID = extractKeyserverIDFromID(input.threadID); + const requests = { [keyserverID]: input }; + + const responses = await callKeyserverEndpoint( + 'join_thread', + requests, + joinThreadOptions, + ); + const response = responses[keyserverID]; + const userInfos = values(response.userInfos); + return { + updatesResult: response.updatesResult, + rawMessageInfos: response.rawMessageInfos, + truncationStatuses: response.truncationStatuses, + userInfos, + keyserverID, + }; + }; +export type UseJoinThreadInput = $ReadOnly< + | { + +thick: false, + ...ClientThreadJoinRequest, + } + | { + +thick: true, + +rawThreadInfo: RawThreadInfo, + }, +>; + +function useJoinThread(): ( + input: UseJoinThreadInput, +) => Promise { + const processAndSendDMOperation = useProcessAndSendDMOperation(); + const viewerID = useSelector( + state => state.currentUserInfo && state.currentUserInfo.id, + ); + const keyserverCall = useKeyserverCall(joinThread); + return React.useCallback( + async (input: UseJoinThreadInput) => { + if (!input.thick) { + const { thick, ...rest } = input; + return await keyserverCall({ ...rest }); + } + + const { rawThreadInfo } = input; + + invariant(viewerID, 'viewerID should be set'); + invariant(rawThreadInfo.thick, 'thread must be thick'); + + const existingThreadDetails = + getCreateThickRawThreadInfoInputFromThreadInfo(rawThreadInfo); + + const op: DMJoinThreadOperation = { + type: 'join_thread', + joinerID: viewerID, + time: Date.now(), + messageID: uuid.v4(), + existingThreadDetails, + }; + + const opSpecification: OutboundDMOperationSpecification = { + type: dmOperationSpecificationTypes.OUTBOUND, + op, + recipients: { + type: 'all_thread_members', + threadID: + rawThreadInfo.type === thickThreadTypes.THICK_SIDEBAR && + rawThreadInfo.parentThreadID + ? rawThreadInfo.parentThreadID + : rawThreadInfo.id, + }, + }; + + await processAndSendDMOperation(opSpecification); + return ({ + updatesResult: { newUpdates: [] }, + rawMessageInfos: [], + truncationStatuses: {}, + userInfos: [], + }: ThreadJoinPayload); + }, + [keyserverCall, processAndSendDMOperation, viewerID], + ); +} + +export type LeaveThreadInput = { + +threadID: string, +}; +const leaveThreadEndpointOptions = { + timeout: permissionsAndAuthRelatedRequestTimeout, +}; +const leaveThread = + ( + callKeyserverEndpoint: CallKeyserverEndpoint, + ): ((input: LeaveThreadInput) => Promise) => + async input => { + const keyserverID = extractKeyserverIDFromID(input.threadID); + const requests = { [keyserverID]: input }; + + const responses = await callKeyserverEndpoint( + 'leave_thread', + requests, + leaveThreadEndpointOptions, + ); + const response = responses[keyserverID]; + return { + updatesResult: response.updatesResult, + }; + }; + +function useLeaveThread(): ( + input: LeaveThreadInput, +) => Promise { + return useKeyserverCall(leaveThread); +} + +const fetchThreadMedia = + ( + callKeyserverEndpoint: CallKeyserverEndpoint, + ): ((input: ThreadFetchMediaRequest) => Promise) => + async input => { + const keyserverID = extractKeyserverIDFromID(input.threadID); + const requests = { [keyserverID]: input }; + + const responses = await callKeyserverEndpoint( + 'fetch_thread_media', + requests, + ); + const response = responses[keyserverID]; + return { media: response.media }; + }; + +function useFetchThreadMedia(): ( + input: ThreadFetchMediaRequest, +) => Promise { + return useKeyserverCall(fetchThreadMedia); +} + +const modifyCommunityRole = + ( + callKeyserverEndpoint: CallKeyserverEndpoint, + ): ((input: RoleModificationRequest) => Promise) => + async input => { + const keyserverID = extractKeyserverIDFromID(input.community); + const requests = { [keyserverID]: input }; + + const responses = await callKeyserverEndpoint( + 'modify_community_role', + requests, + ); + const response = responses[keyserverID]; + return { + threadInfo: response.threadInfo, + updatesResult: response.updatesResult, + }; + }; + +function useModifyCommunityRole(): ( + input: RoleModificationRequest, +) => Promise { + return useKeyserverCall(modifyCommunityRole); +} + +const deleteCommunityRole = + ( + callKeyserverEndpoint: CallKeyserverEndpoint, + ): ((input: RoleDeletionRequest) => Promise) => + async input => { + const keyserverID = extractKeyserverIDFromID(input.community); + const requests = { [keyserverID]: input }; + + const responses = await callKeyserverEndpoint( + 'delete_community_role', + requests, + ); + const response = responses[keyserverID]; + return { + threadInfo: response.threadInfo, + updatesResult: response.updatesResult, + }; + }; + +function useDeleteCommunityRole(): ( + input: RoleDeletionRequest, +) => Promise { + return useKeyserverCall(deleteCommunityRole); +} + +export { + useDeleteCommunityRole, + useModifyCommunityRole, + useFetchThreadMedia, + useLeaveThread, + useJoinThread, + useNewThinThread, + useChangeThreadMemberRoles, + useRemoveUsersFromThread, + useChangeThreadSettings, + useDeleteThread, +}; diff --git a/lib/shared/community-utils.js b/lib/shared/community-utils.js --- a/lib/shared/community-utils.js +++ b/lib/shared/community-utils.js @@ -10,11 +10,9 @@ useDeleteFarcasterChannelTag, } from '../actions/community-actions.js'; import { addKeyserverActionType } from '../actions/keyserver-actions.js'; -import { - joinThreadActionTypes, - useJoinThread, -} from '../actions/thread-actions.js'; +import { joinThreadActionTypes } from '../actions/thread-actions.js'; import type { LinkStatus } from '../hooks/invite-links.js'; +import { useJoinThread } from '../hooks/thread-hooks.js'; import { extractKeyserverIDFromID } from '../keyserver-conn/keyserver-call-utils.js'; import { createLoadingStatusSelector } from '../selectors/loading-selectors.js'; import { isLoggedInToKeyserver } from '../selectors/user-selectors.js'; diff --git a/lib/shared/messages/text-message-spec.js b/lib/shared/messages/text-message-spec.js --- a/lib/shared/messages/text-message-spec.js +++ b/lib/shared/messages/text-message-spec.js @@ -10,10 +10,8 @@ type RawMessageInfoFromServerDBRowParams, } from './message-spec.js'; import { assertSingleMessageInfo, joinResult } from './utils.js'; -import { - changeThreadSettingsActionTypes, - useChangeThreadSettings, -} from '../../actions/thread-actions.js'; +import { changeThreadSettingsActionTypes } from '../../actions/thread-actions.js'; +import { useChangeThreadSettings } from '../../hooks/thread-hooks.js'; import { messageTypes } from '../../types/message-types-enum.js'; import type { ClientDBMessageInfo, diff --git a/lib/shared/thread-actions-utils.js b/lib/shared/thread-actions-utils.js --- a/lib/shared/thread-actions-utils.js +++ b/lib/shared/thread-actions-utils.js @@ -10,8 +10,8 @@ import { newThreadActionTypes, removeUsersFromThreadActionTypes, - type RemoveUsersFromThreadInput, } from '../actions/thread-actions.js'; +import type { RemoveUsersFromThreadInput } from '../hooks/thread-hooks.js'; import type { CalendarQuery } from '../types/entry-types.js'; import type { RelativeMemberInfo, 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 @@ -14,8 +14,8 @@ type SendMultimediaMessageInput, type SendTextMessageInput, } from '../../actions/message-actions.js'; -import type { UseChangeThreadSettingsInput } from '../../actions/thread-actions.js'; import { type MediaMetadataReassignmentAction } from '../../actions/upload-actions.js'; +import type { UseChangeThreadSettingsInput } from '../../hooks/thread-hooks.js'; import type { ProcessOutboundP2PMessagesResult } from '../../tunnelbroker/peer-to-peer-context.js'; import type { TunnelbrokerSocketState } from '../../tunnelbroker/tunnelbroker-context.js'; import type { diff --git a/native/chat/chat-input-bar.react.js b/native/chat/chat-input-bar.react.js --- a/native/chat/chat-input-bar.react.js +++ b/native/chat/chat-input-bar.react.js @@ -33,12 +33,12 @@ import { joinThreadActionTypes, newThreadActionTypes, - useJoinThread, } from 'lib/actions/thread-actions.js'; import { useChatMentionContext, useThreadChatMentionCandidates, } from 'lib/hooks/chat-mention-hooks.js'; +import { useJoinThread } from 'lib/hooks/thread-hooks.js'; import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js'; import { threadInfoSelector } from 'lib/selectors/thread-selectors.js'; import { colorIsDark } from 'lib/shared/color-utils.js'; diff --git a/native/chat/compose-subchannel.react.js b/native/chat/compose-subchannel.react.js --- a/native/chat/compose-subchannel.react.js +++ b/native/chat/compose-subchannel.react.js @@ -7,11 +7,9 @@ import * as React from 'react'; import { Text, View } from 'react-native'; -import { - newThreadActionTypes, - useNewThinThread, -} from 'lib/actions/thread-actions.js'; +import { newThreadActionTypes } from 'lib/actions/thread-actions.js'; import { useENSNames } from 'lib/hooks/ens-cache.js'; +import { useNewThinThread } from 'lib/hooks/thread-hooks.js'; import { threadInfoSelector } from 'lib/selectors/thread-selectors.js'; import { userInfoSelectorForPotentialMembers } from 'lib/selectors/user-selectors.js'; import { usePotentialMemberItems } from 'lib/shared/search-utils.js'; diff --git a/native/chat/settings/add-users-modal.react.js b/native/chat/settings/add-users-modal.react.js --- a/native/chat/settings/add-users-modal.react.js +++ b/native/chat/settings/add-users-modal.react.js @@ -3,11 +3,9 @@ import * as React from 'react'; import { ActivityIndicator, Text, View } from 'react-native'; -import { - changeThreadSettingsActionTypes, - useChangeThreadSettings, -} from 'lib/actions/thread-actions.js'; +import { changeThreadSettingsActionTypes } from 'lib/actions/thread-actions.js'; import { useENSNames } from 'lib/hooks/ens-cache.js'; +import { useChangeThreadSettings } from 'lib/hooks/thread-hooks.js'; import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js'; import { threadInfoSelector } from 'lib/selectors/thread-selectors.js'; import { userInfoSelectorForPotentialMembers } from 'lib/selectors/user-selectors.js'; diff --git a/native/chat/settings/color-selector-modal.react.js b/native/chat/settings/color-selector-modal.react.js --- a/native/chat/settings/color-selector-modal.react.js +++ b/native/chat/settings/color-selector-modal.react.js @@ -4,11 +4,9 @@ import * as React from 'react'; import { TouchableHighlight } from 'react-native'; -import { - changeThreadSettingsActionTypes, - useChangeThreadSettings, - type UseChangeThreadSettingsInput, -} from 'lib/actions/thread-actions.js'; +import { changeThreadSettingsActionTypes } from 'lib/actions/thread-actions.js'; +import { useChangeThreadSettings } from 'lib/hooks/thread-hooks.js'; +import type { UseChangeThreadSettingsInput } from 'lib/hooks/thread-hooks.js'; import type { ThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js'; import { type ChangeThreadSettingsPayload } from 'lib/types/thread-types.js'; import { diff --git a/native/chat/settings/delete-thread.react.js b/native/chat/settings/delete-thread.react.js --- a/native/chat/settings/delete-thread.react.js +++ b/native/chat/settings/delete-thread.react.js @@ -10,11 +10,9 @@ } from 'react-native'; import { ScrollView } from 'react-native-gesture-handler'; -import type { DeleteThreadInput } from 'lib/actions/thread-actions.js'; -import { - deleteThreadActionTypes, - useDeleteThread, -} from 'lib/actions/thread-actions.js'; +import { deleteThreadActionTypes } from 'lib/actions/thread-actions.js'; +import { useDeleteThread } from 'lib/hooks/thread-hooks.js'; +import type { DeleteThreadInput } from 'lib/hooks/thread-hooks.js'; import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js'; import { containedThreadInfos, diff --git a/native/chat/settings/thread-settings-description.react.js b/native/chat/settings/thread-settings-description.react.js --- a/native/chat/settings/thread-settings-description.react.js +++ b/native/chat/settings/thread-settings-description.react.js @@ -9,11 +9,9 @@ View, } from 'react-native'; -import { - changeThreadSettingsActionTypes, - useChangeThreadSettings, - type UseChangeThreadSettingsInput, -} from 'lib/actions/thread-actions.js'; +import { changeThreadSettingsActionTypes } from 'lib/actions/thread-actions.js'; +import { useChangeThreadSettings } from 'lib/hooks/thread-hooks.js'; +import type { UseChangeThreadSettingsInput } from 'lib/hooks/thread-hooks.js'; import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js'; import { useThreadHasPermission } from 'lib/shared/thread-utils.js'; import type { LoadingStatus } from 'lib/types/loading-types.js'; diff --git a/native/chat/settings/thread-settings-leave-thread.react.js b/native/chat/settings/thread-settings-leave-thread.react.js --- a/native/chat/settings/thread-settings-leave-thread.react.js +++ b/native/chat/settings/thread-settings-leave-thread.react.js @@ -5,11 +5,9 @@ import { ActivityIndicator, Text, View } from 'react-native'; import uuid from 'uuid'; -import type { LeaveThreadInput } from 'lib/actions/thread-actions.js'; -import { - leaveThreadActionTypes, - useLeaveThread, -} from 'lib/actions/thread-actions.js'; +import { leaveThreadActionTypes } from 'lib/actions/thread-actions.js'; +import { useLeaveThread } from 'lib/hooks/thread-hooks.js'; +import type { LeaveThreadInput } from 'lib/hooks/thread-hooks.js'; import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js'; import { otherUsersButNoOtherAdmins } from 'lib/selectors/thread-selectors.js'; import { diff --git a/native/chat/settings/thread-settings-media-gallery.react.js b/native/chat/settings/thread-settings-media-gallery.react.js --- a/native/chat/settings/thread-settings-media-gallery.react.js +++ b/native/chat/settings/thread-settings-media-gallery.react.js @@ -7,7 +7,7 @@ import type { ViewStyleProp } from 'react-native/Libraries/StyleSheet/StyleSheet'; import { FlatList } from 'react-native-gesture-handler'; -import { useFetchThreadMedia } from 'lib/actions/thread-actions.js'; +import { useFetchThreadMedia } from 'lib/hooks/thread-hooks.js'; import type { MediaInfo, Media } from 'lib/types/media-types'; import { diff --git a/native/chat/settings/thread-settings-member-tooltip-modal.react.js b/native/chat/settings/thread-settings-member-tooltip-modal.react.js --- a/native/chat/settings/thread-settings-member-tooltip-modal.react.js +++ b/native/chat/settings/thread-settings-member-tooltip-modal.react.js @@ -2,7 +2,7 @@ import * as React from 'react'; -import { useRemoveUsersFromThread } from 'lib/actions/thread-actions.js'; +import { useRemoveUsersFromThread } from 'lib/hooks/thread-hooks.js'; import { removeMemberFromThread } from 'lib/shared/thread-actions-utils.js'; import { stringForUser } from 'lib/shared/user-utils.js'; import type { diff --git a/native/chat/settings/thread-settings-name.react.js b/native/chat/settings/thread-settings-name.react.js --- a/native/chat/settings/thread-settings-name.react.js +++ b/native/chat/settings/thread-settings-name.react.js @@ -9,11 +9,9 @@ View, } from 'react-native'; -import { - changeThreadSettingsActionTypes, - useChangeThreadSettings, - type UseChangeThreadSettingsInput, -} from 'lib/actions/thread-actions.js'; +import { changeThreadSettingsActionTypes } from 'lib/actions/thread-actions.js'; +import { useChangeThreadSettings } from 'lib/hooks/thread-hooks.js'; +import type { UseChangeThreadSettingsInput } from 'lib/hooks/thread-hooks.js'; import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js'; import type { LoadingStatus } from 'lib/types/loading-types.js'; import type { ResolvedThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js'; diff --git a/native/community-creation/community-configuration.react.js b/native/community-creation/community-configuration.react.js --- a/native/community-creation/community-configuration.react.js +++ b/native/community-creation/community-configuration.react.js @@ -3,10 +3,8 @@ import * as React from 'react'; import { Text, View } from 'react-native'; -import { - useNewThinThread, - newThreadActionTypes, -} from 'lib/actions/thread-actions.js'; +import { newThreadActionTypes } from 'lib/actions/thread-actions.js'; +import { useNewThinThread } from 'lib/hooks/thread-hooks.js'; import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js'; import { threadInfoSelector } from 'lib/selectors/thread-selectors.js'; import type { LoadingStatus } from 'lib/types/loading-types.js'; diff --git a/native/components/community-list-item.react.js b/native/components/community-list-item.react.js --- a/native/components/community-list-item.react.js +++ b/native/components/community-list-item.react.js @@ -4,10 +4,8 @@ import { useState } from 'react'; import { View } from 'react-native'; -import { - leaveThreadActionTypes, - useLeaveThread, -} from 'lib/actions/thread-actions.js'; +import { leaveThreadActionTypes } from 'lib/actions/thread-actions.js'; +import { useLeaveThread } from 'lib/hooks/thread-hooks.js'; import { threadInfoSelector } from 'lib/selectors/thread-selectors.js'; import { useJoinCommunity } from 'lib/shared/community-utils.js'; import { diff --git a/native/input/input-state-container.react.js b/native/input/input-state-container.react.js --- a/native/input/input-state-container.react.js +++ b/native/input/input-state-container.react.js @@ -12,7 +12,6 @@ sendTextMessageActionTypes, } from 'lib/actions/message-actions.js'; import { queueReportsActionType } from 'lib/actions/report-actions.js'; -import { useNewThinThread } from 'lib/actions/thread-actions.js'; import { type BlobServiceUploadAction, type BlobServiceUploadResult, @@ -23,7 +22,7 @@ useInputStateContainerSendMultimediaMessage, useInputStateContainerSendTextMessage, } from 'lib/hooks/input-state-container-hooks.js'; -import { useNewThickThread } from 'lib/hooks/thread-hooks.js'; +import { useNewThickThread, useNewThinThread } from 'lib/hooks/thread-hooks.js'; import { useBlobServiceUpload } from 'lib/hooks/upload-hooks.js'; import type { CallSingleKeyserverEndpointOptions, 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,10 +6,8 @@ import { Text, View } from 'react-native'; import { TouchableOpacity } from 'react-native-gesture-handler'; -import { - useChangeThreadMemberRoles, - changeThreadMemberRolesActionTypes, -} from 'lib/actions/thread-actions.js'; +import { changeThreadMemberRolesActionTypes } from 'lib/actions/thread-actions.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'; diff --git a/native/roles/create-roles-header-right-button.react.js b/native/roles/create-roles-header-right-button.react.js --- a/native/roles/create-roles-header-right-button.react.js +++ b/native/roles/create-roles-header-right-button.react.js @@ -5,10 +5,8 @@ import * as React from 'react'; import { TouchableOpacity, Text } from 'react-native'; -import { - useModifyCommunityRole, - modifyCommunityRoleActionTypes, -} from 'lib/actions/thread-actions.js'; +import { modifyCommunityRoleActionTypes } from 'lib/actions/thread-actions.js'; +import { useModifyCommunityRole } from 'lib/hooks/thread-hooks.js'; import { values } from 'lib/utils/objects.js'; import { useDispatchActionPromise } from 'lib/utils/redux-promise-utils.js'; diff --git a/native/roles/role-utils.react.js b/native/roles/role-utils.react.js --- a/native/roles/role-utils.react.js +++ b/native/roles/role-utils.react.js @@ -2,10 +2,8 @@ import * as React from 'react'; -import { - deleteCommunityRoleActionTypes, - useDeleteCommunityRole, -} from 'lib/actions/thread-actions.js'; +import { deleteCommunityRoleActionTypes } from 'lib/actions/thread-actions.js'; +import { useDeleteCommunityRole } from 'lib/hooks/thread-hooks.js'; import type { ThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js'; import { useDispatchActionPromise } from 'lib/utils/redux-promise-utils.js'; import { constructRoleDeletionMessagePrompt } from 'lib/utils/role-utils.js'; diff --git a/web/chat/chat-input-bar.react.js b/web/chat/chat-input-bar.react.js --- a/web/chat/chat-input-bar.react.js +++ b/web/chat/chat-input-bar.react.js @@ -7,14 +7,14 @@ import { joinThreadActionTypes, newThreadActionTypes, - useJoinThread, } from 'lib/actions/thread-actions.js'; -import type { UseJoinThreadInput } from 'lib/actions/thread-actions.js'; import SWMansionIcon from 'lib/components/swmansion-icon.react.js'; import { useChatMentionContext, useThreadChatMentionCandidates, } from 'lib/hooks/chat-mention-hooks.js'; +import { useJoinThread } from 'lib/hooks/thread-hooks.js'; +import type { UseJoinThreadInput } from 'lib/hooks/thread-hooks.js'; import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js'; import { threadInfoSelector } from 'lib/selectors/thread-selectors.js'; import { getNextLocalID } from 'lib/shared/id-utils.js'; diff --git a/web/chat/thread-menu.react.js b/web/chat/thread-menu.react.js --- a/web/chat/thread-menu.react.js +++ b/web/chat/thread-menu.react.js @@ -4,13 +4,11 @@ import * as React from 'react'; import uuid from 'uuid'; -import { - leaveThreadActionTypes, - useLeaveThread, -} from 'lib/actions/thread-actions.js'; +import { leaveThreadActionTypes } from 'lib/actions/thread-actions.js'; import { useModalContext } from 'lib/components/modal-provider.react.js'; import SWMansionIcon from 'lib/components/swmansion-icon.react.js'; import { usePromoteSidebar } from 'lib/hooks/promote-sidebar.react.js'; +import { useLeaveThread } from 'lib/hooks/thread-hooks.js'; import { childThreadInfos } from 'lib/selectors/thread-selectors.js'; import { type OutboundDMOperationSpecification, diff --git a/web/input/input-state-container.react.js b/web/input/input-state-container.react.js --- a/web/input/input-state-container.react.js +++ b/web/input/input-state-container.react.js @@ -16,7 +16,6 @@ sendTextMessageActionTypes, } from 'lib/actions/message-actions.js'; import { queueReportsActionType } from 'lib/actions/report-actions.js'; -import { useNewThinThread } from 'lib/actions/thread-actions.js'; import { type BlobServiceUploadAction, type DeleteUploadInput, @@ -31,7 +30,7 @@ useInputStateContainerSendMultimediaMessage, useInputStateContainerSendTextMessage, } from 'lib/hooks/input-state-container-hooks.js'; -import { useNewThickThread } from 'lib/hooks/thread-hooks.js'; +import { useNewThickThread, useNewThinThread } from 'lib/hooks/thread-hooks.js'; import { useBlobServiceUpload, useDeleteUpload, diff --git a/web/modals/threads/create/compose-subchannel-modal.react.js b/web/modals/threads/create/compose-subchannel-modal.react.js --- a/web/modals/threads/create/compose-subchannel-modal.react.js +++ b/web/modals/threads/create/compose-subchannel-modal.react.js @@ -2,10 +2,8 @@ import * as React from 'react'; -import { - newThreadActionTypes, - useNewThinThread, -} from 'lib/actions/thread-actions.js'; +import { newThreadActionTypes } from 'lib/actions/thread-actions.js'; +import { useNewThinThread } from 'lib/hooks/thread-hooks.js'; import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js'; import type { ThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js'; import { threadTypes } from 'lib/types/thread-types-enum.js'; diff --git a/web/modals/threads/gallery/thread-settings-media-gallery.react.js b/web/modals/threads/gallery/thread-settings-media-gallery.react.js --- a/web/modals/threads/gallery/thread-settings-media-gallery.react.js +++ b/web/modals/threads/gallery/thread-settings-media-gallery.react.js @@ -3,8 +3,8 @@ import invariant from 'invariant'; import * as React from 'react'; -import { useFetchThreadMedia } from 'lib/actions/thread-actions.js'; import { useModalContext } from 'lib/components/modal-provider.react.js'; +import { useFetchThreadMedia } from 'lib/hooks/thread-hooks.js'; import { encryptedMediaBlobURI, encryptedVideoThumbnailBlobURI, diff --git a/web/modals/threads/members/add-members-modal.react.js b/web/modals/threads/members/add-members-modal.react.js --- a/web/modals/threads/members/add-members-modal.react.js +++ b/web/modals/threads/members/add-members-modal.react.js @@ -2,10 +2,8 @@ import * as React from 'react'; -import { - changeThreadSettingsActionTypes, - useChangeThreadSettings, -} from 'lib/actions/thread-actions.js'; +import { changeThreadSettingsActionTypes } from 'lib/actions/thread-actions.js'; +import { useChangeThreadSettings } from 'lib/hooks/thread-hooks.js'; import { threadInfoSelector } from 'lib/selectors/thread-selectors.js'; import { useAddDMThreadMembers } from 'lib/shared/dm-ops/dm-op-utils.js'; import { threadTypeIsThick } from 'lib/types/thread-types-enum.js'; 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,12 +3,10 @@ import invariant from 'invariant'; import * as React from 'react'; -import { - changeThreadMemberRolesActionTypes, - useChangeThreadMemberRoles, -} from 'lib/actions/thread-actions.js'; +import { changeThreadMemberRolesActionTypes } from 'lib/actions/thread-actions.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'; import { otherUsersButNoOtherAdmins } from 'lib/selectors/thread-selectors.js'; import { roleIsAdminRole } from 'lib/shared/thread-utils.js'; import type { diff --git a/web/modals/threads/members/member.react.js b/web/modals/threads/members/member.react.js --- a/web/modals/threads/members/member.react.js +++ b/web/modals/threads/members/member.react.js @@ -2,9 +2,9 @@ import * as React from 'react'; -import { useRemoveUsersFromThread } from 'lib/actions/thread-actions.js'; import { useModalContext } from 'lib/components/modal-provider.react.js'; import SWMansionIcon from 'lib/components/swmansion-icon.react.js'; +import { useRemoveUsersFromThread } from 'lib/hooks/thread-hooks.js'; import { removeMemberFromThread } from 'lib/shared/thread-actions-utils.js'; import { useAvailableThreadMemberActions } from 'lib/shared/thread-utils.js'; import { stringForUser } from 'lib/shared/user-utils.js'; diff --git a/web/modals/threads/settings/thread-settings-utils.js b/web/modals/threads/settings/thread-settings-utils.js --- a/web/modals/threads/settings/thread-settings-utils.js +++ b/web/modals/threads/settings/thread-settings-utils.js @@ -4,11 +4,13 @@ import { changeThreadSettingsActionTypes, - useChangeThreadSettings, deleteThreadActionTypes, - useDeleteThread, } from 'lib/actions/thread-actions.js'; import { useModalContext } from 'lib/components/modal-provider.react.js'; +import { + useChangeThreadSettings, + useDeleteThread, +} from 'lib/hooks/thread-hooks.js'; import { containedThreadInfos } from 'lib/selectors/thread-selectors.js'; import { type SetState } from 'lib/types/hook-types.js'; import type { ThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js'; diff --git a/web/roles/create-roles-modal.react.js b/web/roles/create-roles-modal.react.js --- a/web/roles/create-roles-modal.react.js +++ b/web/roles/create-roles-modal.react.js @@ -4,11 +4,9 @@ import invariant from 'invariant'; import * as React from 'react'; -import { - modifyCommunityRoleActionTypes, - useModifyCommunityRole, -} from 'lib/actions/thread-actions.js'; +import { modifyCommunityRoleActionTypes } from 'lib/actions/thread-actions.js'; import { useModalContext } from 'lib/components/modal-provider.react.js'; +import { useModifyCommunityRole } from 'lib/hooks/thread-hooks.js'; import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js'; import type { LoadingStatus } from 'lib/types/loading-types.js'; import type { ThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js'; diff --git a/web/roles/delete-role-modal.react.js b/web/roles/delete-role-modal.react.js --- a/web/roles/delete-role-modal.react.js +++ b/web/roles/delete-role-modal.react.js @@ -2,11 +2,9 @@ import * as React from 'react'; -import { - deleteCommunityRoleActionTypes, - useDeleteCommunityRole, -} from 'lib/actions/thread-actions.js'; +import { deleteCommunityRoleActionTypes } from 'lib/actions/thread-actions.js'; import { useModalContext } from 'lib/components/modal-provider.react.js'; +import { useDeleteCommunityRole } from 'lib/hooks/thread-hooks.js'; import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js'; import { useRoleMemberCountsForCommunity } from 'lib/shared/thread-utils.js'; import type { LoadingStatus } from 'lib/types/loading-types.js'; diff --git a/web/sidebar/community-creation/community-creation-modal.react.js b/web/sidebar/community-creation/community-creation-modal.react.js --- a/web/sidebar/community-creation/community-creation-modal.react.js +++ b/web/sidebar/community-creation/community-creation-modal.react.js @@ -2,11 +2,9 @@ import * as React from 'react'; -import { - useNewThinThread, - newThreadActionTypes, -} from 'lib/actions/thread-actions.js'; +import { newThreadActionTypes } from 'lib/actions/thread-actions.js'; import { useModalContext } from 'lib/components/modal-provider.react.js'; +import { useNewThinThread } from 'lib/hooks/thread-hooks.js'; import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js'; import type { LoadingStatus } from 'lib/types/loading-types.js'; import { threadTypes } from 'lib/types/thread-types-enum.js';