diff --git a/lib/shared/reaction-utils.js b/lib/shared/reaction-utils.js
--- a/lib/shared/reaction-utils.js
+++ b/lib/shared/reaction-utils.js
@@ -1,20 +1,38 @@
// @flow
+import invariant from 'invariant';
import _sortBy from 'lodash/fp/sortBy.js';
import * as React from 'react';
-
+import uuid from 'uuid';
+
+import {
+ type OutboundDMOperationSpecification,
+ dmOperationSpecificationTypes,
+} from './dm-ops/dm-op-types.js';
+import { useProcessAndSendDMOperation } from './dm-ops/process-dm-ops.js';
+import { getNextLocalID } from './message-utils.js';
import { relationshipBlockedInEitherDirection } from './relationship-utils.js';
import { useThreadHasPermission } from './thread-utils.js';
import { stringForUserExplicit } from './user-utils.js';
+import { sendReactionMessageActionTypes } from '../actions/message-actions.js';
import { useENSNames } from '../hooks/ens-cache.js';
+import { useSendReactionMessage } from '../hooks/message-hooks.js';
import type { ReactionInfo } from '../selectors/chat-selectors.js';
+import type { DMSendReactionMessageOperation } from '../types/dm-ops.js';
+import { messageTypes } from '../types/message-types-enum.js';
import type {
ComposableMessageInfo,
RobotextMessageInfo,
} from '../types/message-types.js';
+import type { RawReactionMessageInfo } from '../types/messages/reaction.js';
import type { ThreadInfo } from '../types/minimally-encoded-thread-permissions-types.js';
import { threadPermissions } from '../types/thread-permission-types.js';
-import { threadTypeIsThick } from '../types/thread-types-enum.js';
+import {
+ thickThreadTypes,
+ threadTypeIsThick,
+} from '../types/thread-types-enum.js';
+import { getMessageForException, SendMessageError } from '../utils/errors.js';
+import { useDispatchActionPromise } from '../utils/redux-promise-utils.js';
import { useSelector } from '../utils/redux-utils.js';
function useViewerAlreadySelectedMessageReactions(
@@ -106,8 +124,126 @@
);
}
+function useSendReactionBase(
+ messageID: ?string,
+ threadInfo: ThreadInfo,
+ reactions: ReactionInfo,
+ showErrorAlert: () => mixed,
+): (reaction: string) => mixed {
+ const viewerID = useSelector(
+ state => state.currentUserInfo && state.currentUserInfo.id,
+ );
+
+ const callSendReactionMessage = useSendReactionMessage();
+ const dispatchActionPromise = useDispatchActionPromise();
+ const processAndSendDMOperation = useProcessAndSendDMOperation();
+
+ return React.useCallback(
+ reaction => {
+ if (!messageID) {
+ return;
+ }
+
+ const localID = getNextLocalID();
+
+ invariant(viewerID, 'viewerID should be set');
+
+ const viewerReacted = reactions[reaction]
+ ? reactions[reaction].viewerReacted
+ : false;
+ const action = viewerReacted ? 'remove_reaction' : 'add_reaction';
+
+ const threadID = threadInfo.id;
+
+ if (threadTypeIsThick(threadInfo.type)) {
+ const op: DMSendReactionMessageOperation = {
+ type: 'send_reaction_message',
+ threadID,
+ creatorID: viewerID,
+ time: Date.now(),
+ messageID: uuid.v4(),
+ targetMessageID: messageID,
+ reaction,
+ action,
+ };
+ const opSpecification: OutboundDMOperationSpecification = {
+ type: dmOperationSpecificationTypes.OUTBOUND,
+ op,
+ recipients: {
+ type: 'all_thread_members',
+ threadID:
+ threadInfo.type === thickThreadTypes.THICK_SIDEBAR &&
+ threadInfo.parentThreadID
+ ? threadInfo.parentThreadID
+ : threadInfo.id,
+ },
+ };
+ void processAndSendDMOperation(opSpecification);
+ return;
+ }
+
+ const reactionMessagePromise = (async () => {
+ try {
+ const result = await callSendReactionMessage({
+ threadID,
+ localID,
+ targetMessageID: messageID,
+ reaction,
+ action,
+ });
+ return {
+ localID,
+ serverID: result.id,
+ threadID,
+ time: result.time,
+ };
+ } catch (e) {
+ showErrorAlert();
+ const exceptionMessage = getMessageForException(e) ?? '';
+ throw new SendMessageError(
+ `Exception while sending reaction: ${exceptionMessage}`,
+ localID,
+ threadID,
+ );
+ }
+ })();
+
+ const startingPayload: RawReactionMessageInfo = {
+ type: messageTypes.REACTION,
+ threadID,
+ localID,
+ creatorID: viewerID,
+ time: Date.now(),
+ targetMessageID: messageID,
+ reaction,
+ action,
+ };
+
+ void dispatchActionPromise(
+ sendReactionMessageActionTypes,
+ reactionMessagePromise,
+ undefined,
+ startingPayload,
+ );
+ },
+ [
+ messageID,
+ viewerID,
+ reactions,
+ threadInfo.id,
+ threadInfo.type,
+ threadInfo.parentThreadID,
+ dispatchActionPromise,
+ processAndSendDMOperation,
+ callSendReactionMessage,
+ showErrorAlert,
+ ],
+ );
+}
+
export {
useViewerAlreadySelectedMessageReactions,
useMessageReactionsList,
useCanCreateReactionFromMessage,
+ useSendReactionBase,
};
diff --git a/native/chat/reaction-message-utils.js b/native/chat/reaction-message-utils.js
--- a/native/chat/reaction-message-utils.js
+++ b/native/chat/reaction-message-utils.js
@@ -1,28 +1,10 @@
// @flow
-import invariant from 'invariant';
import * as React from 'react';
-import uuid from 'uuid';
-import { sendReactionMessageActionTypes } from 'lib/actions/message-actions.js';
-import { useSendReactionMessage } from 'lib/hooks/message-hooks.js';
import type { ReactionInfo } from 'lib/selectors/chat-selectors.js';
-import {
- dmOperationSpecificationTypes,
- type OutboundDMOperationSpecification,
-} from 'lib/shared/dm-ops/dm-op-types.js';
-import { useProcessAndSendDMOperation } from 'lib/shared/dm-ops/process-dm-ops.js';
-import { getNextLocalID } from 'lib/shared/message-utils.js';
-import type { DMSendReactionMessageOperation } from 'lib/types/dm-ops.js';
-import { messageTypes } from 'lib/types/message-types-enum.js';
-import type { RawReactionMessageInfo } from 'lib/types/messages/reaction.js';
+import { useSendReactionBase } from 'lib/shared/reaction-utils.js';
import type { ThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types';
-import {
- thickThreadTypes,
- threadTypeIsThick,
-} from 'lib/types/thread-types-enum.js';
-import { SendMessageError, getMessageForException } from 'lib/utils/errors.js';
-import { useDispatchActionPromise } from 'lib/utils/redux-promise-utils.js';
import { useSelector } from '../redux/redux-utils.js';
import type {
@@ -31,125 +13,27 @@
} from '../types/layout-types.js';
import Alert from '../utils/alert.js';
+function showReactionErrorAlert() {
+ Alert.alert(
+ 'Couldn’t send the reaction',
+ 'Please try again later',
+ [{ text: 'OK' }],
+ {
+ cancelable: true,
+ },
+ );
+}
+
function useSendReaction(
messageID: ?string,
threadInfo: ThreadInfo,
reactions: ReactionInfo,
): (reaction: string) => mixed {
- const viewerID = useSelector(
- state => state.currentUserInfo && state.currentUserInfo.id,
- );
-
- const callSendReactionMessage = useSendReactionMessage();
- const dispatchActionPromise = useDispatchActionPromise();
- const processAndSendDMOperation = useProcessAndSendDMOperation();
-
- return React.useCallback(
- reaction => {
- if (!messageID) {
- return;
- }
-
- const localID = getNextLocalID();
-
- invariant(viewerID, 'viewerID should be set');
-
- const viewerReacted = reactions[reaction]
- ? reactions[reaction].viewerReacted
- : false;
- const action = viewerReacted ? 'remove_reaction' : 'add_reaction';
-
- const threadID = threadInfo.id;
-
- if (threadTypeIsThick(threadInfo.type)) {
- const op: DMSendReactionMessageOperation = {
- type: 'send_reaction_message',
- threadID,
- creatorID: viewerID,
- time: Date.now(),
- messageID: uuid.v4(),
- targetMessageID: messageID,
- reaction,
- action,
- };
- const opSpecification: OutboundDMOperationSpecification = {
- type: dmOperationSpecificationTypes.OUTBOUND,
- op,
- recipients: {
- type: 'all_thread_members',
- threadID:
- threadInfo.type === thickThreadTypes.THICK_SIDEBAR &&
- threadInfo.parentThreadID
- ? threadInfo.parentThreadID
- : threadInfo.id,
- },
- };
- void processAndSendDMOperation(opSpecification);
- return;
- }
-
- const reactionMessagePromise = (async () => {
- try {
- const result = await callSendReactionMessage({
- threadID,
- localID,
- targetMessageID: messageID,
- reaction,
- action,
- });
- return {
- localID,
- serverID: result.id,
- threadID,
- time: result.time,
- };
- } catch (e) {
- Alert.alert(
- 'Couldn’t send the reaction',
- 'Please try again later',
- [{ text: 'OK' }],
- {
- cancelable: true,
- },
- );
- const exceptionMessage = getMessageForException(e) ?? '';
- throw new SendMessageError(
- `Exception while sending reaction: ${exceptionMessage}`,
- localID,
- threadID,
- );
- }
- })();
-
- const startingPayload: RawReactionMessageInfo = {
- type: messageTypes.REACTION,
- threadID,
- localID,
- creatorID: viewerID,
- time: Date.now(),
- targetMessageID: messageID,
- reaction,
- action,
- };
-
- void dispatchActionPromise(
- sendReactionMessageActionTypes,
- reactionMessagePromise,
- undefined,
- startingPayload,
- );
- },
- [
- messageID,
- viewerID,
- reactions,
- threadInfo.id,
- threadInfo.type,
- threadInfo.parentThreadID,
- dispatchActionPromise,
- processAndSendDMOperation,
- callSendReactionMessage,
- ],
+ return useSendReactionBase(
+ messageID,
+ threadInfo,
+ reactions,
+ showReactionErrorAlert,
);
}
diff --git a/web/chat/reaction-message-utils.js b/web/chat/reaction-message-utils.js
--- a/web/chat/reaction-message-utils.js
+++ b/web/chat/reaction-message-utils.js
@@ -1,32 +1,13 @@
// @flow
-import invariant from 'invariant';
import * as React from 'react';
-import uuid from 'uuid';
-import { sendReactionMessageActionTypes } from 'lib/actions/message-actions.js';
import { useModalContext } from 'lib/components/modal-provider.react.js';
-import { useSendReactionMessage } from 'lib/hooks/message-hooks.js';
-import type { ReactionInfo } from 'lib/selectors/chat-selectors';
-import {
- dmOperationSpecificationTypes,
- type OutboundDMOperationSpecification,
-} from 'lib/shared/dm-ops/dm-op-types.js';
-import { useProcessAndSendDMOperation } from 'lib/shared/dm-ops/process-dm-ops.js';
-import { getNextLocalID } from 'lib/shared/message-utils.js';
-import { type DMSendReactionMessageOperation } from 'lib/types/dm-ops.js';
-import { messageTypes } from 'lib/types/message-types-enum.js';
-import type { RawReactionMessageInfo } from 'lib/types/messages/reaction.js';
+import type { ReactionInfo } from 'lib/selectors/chat-selectors.js';
+import { useSendReactionBase } from 'lib/shared/reaction-utils.js';
import type { ThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js';
-import {
- thickThreadTypes,
- threadTypeIsThick,
-} from 'lib/types/thread-types-enum.js';
-import { SendMessageError, getMessageForException } from 'lib/utils/errors.js';
-import { useDispatchActionPromise } from 'lib/utils/redux-promise-utils.js';
import Alert from '../modals/alert.react.js';
-import { useSelector } from '../redux/redux-utils.js';
import {
type TooltipSize,
type TooltipPositionStyle,
@@ -40,121 +21,16 @@
): (reaction: string) => mixed {
const { pushModal } = useModalContext();
- const viewerID = useSelector(
- state => state.currentUserInfo && state.currentUserInfo.id,
- );
-
- const callSendReactionMessage = useSendReactionMessage();
- const dispatchActionPromise = useDispatchActionPromise();
- const processAndSendDMOperation = useProcessAndSendDMOperation();
-
- return React.useCallback(
- reaction => {
- if (!messageID) {
- return;
- }
-
- const localID = getNextLocalID();
-
- invariant(viewerID, 'viewerID should be set');
-
- const viewerReacted = reactions[reaction]
- ? reactions[reaction].viewerReacted
- : false;
- const action = viewerReacted ? 'remove_reaction' : 'add_reaction';
-
- const threadID = threadInfo.id;
-
- if (threadTypeIsThick(threadInfo.type)) {
- const op: DMSendReactionMessageOperation = {
- type: 'send_reaction_message',
- threadID,
- creatorID: viewerID,
- time: Date.now(),
- messageID: uuid.v4(),
- targetMessageID: messageID,
- reaction,
- action,
- };
- const opSpecification: OutboundDMOperationSpecification = {
- type: dmOperationSpecificationTypes.OUTBOUND,
- op,
- recipients: {
- type: 'all_thread_members',
- threadID:
- threadInfo.type === thickThreadTypes.THICK_SIDEBAR &&
- threadInfo.parentThreadID
- ? threadInfo.parentThreadID
- : threadInfo.id,
- },
- };
- void processAndSendDMOperation(opSpecification);
- return;
- }
-
- const reactionMessagePromise = (async () => {
- try {
- const result = await callSendReactionMessage({
- threadID,
- localID,
- targetMessageID: messageID,
- reaction,
- action,
- });
- const serverID: string = result.id;
- const time: number = result.time;
- return {
- localID,
- serverID,
- threadID,
- time,
- };
- } catch (e) {
- pushModal(
-
- Please try again later
- ,
- );
- const exceptionMessage = getMessageForException(e) ?? '';
- throw new SendMessageError(
- `Exception while sending reaction: ${exceptionMessage}`,
- localID,
- threadID,
- );
- }
- })();
-
- const startingPayload: RawReactionMessageInfo = {
- type: messageTypes.REACTION,
- threadID,
- localID,
- creatorID: viewerID,
- time: Date.now(),
- targetMessageID: messageID,
- reaction,
- action,
- };
-
- void dispatchActionPromise(
- sendReactionMessageActionTypes,
- reactionMessagePromise,
- undefined,
- startingPayload,
- );
- },
- [
- messageID,
- viewerID,
- reactions,
- threadInfo.id,
- threadInfo.type,
- threadInfo.parentThreadID,
- dispatchActionPromise,
- processAndSendDMOperation,
- callSendReactionMessage,
- pushModal,
- ],
+ const showErrorAlert = React.useCallback(
+ () =>
+ pushModal(
+
+ Please try again later
+ ,
+ ),
+ [pushModal],
);
+ return useSendReactionBase(messageID, threadInfo, reactions, showErrorAlert);
}
type EmojiKeyboardPosition = {