diff --git a/lib/actions/message-report-actions.js b/lib/actions/message-report-actions.js new file mode 100644 --- /dev/null +++ b/lib/actions/message-report-actions.js @@ -0,0 +1,22 @@ +// @flow + +import type { + MessageReportCreationRequest, + MessageReportCreationResult, +} from '../types/message-report-types'; +import type { FetchJSON } from '../utils/fetch-json'; + +const sendMessageReportActionTypes = Object.freeze({ + started: 'SEND_MESSAGE_REPORT_STARTED', + success: 'SEND_MESSAGE_REPORT_SUCCESS', + failed: 'SEND_MESSAGE_REPORT_FAILED', +}); +const sendMessageReport = ( + fetchJSON: FetchJSON, +): (( + request: MessageReportCreationRequest, +) => Promise) => async request => { + return await fetchJSON('create_message_report', request); +}; + +export { sendMessageReportActionTypes, sendMessageReport }; diff --git a/lib/reducers/message-reducer.js b/lib/reducers/message-reducer.js --- a/lib/reducers/message-reducer.js +++ b/lib/reducers/message-reducer.js @@ -32,6 +32,7 @@ fetchSingleMostRecentMessagesFromThreadsActionTypes, setMessageStoreMessages, } from '../actions/message-actions'; +import { sendMessageReportActionTypes } from '../actions/message-report-actions'; import { changeThreadSettingsActionTypes, deleteThreadActionTypes, @@ -823,6 +824,16 @@ messagesResult.truncationStatuses, newThreadInfos, ); + } else if (action.type === sendMessageReportActionTypes.success) { + return mergeNewMessages( + messageStore, + [action.payload.messageInfo], + { + [action.payload.messageInfo.threadID]: + messageTruncationStatus.UNCHANGED, + }, + newThreadInfos, + ); } else if (action.type === registerActionTypes.success) { const truncationStatuses = {}; for (const messageInfo of action.payload.rawMessageInfos) { diff --git a/lib/types/redux-types.js b/lib/types/redux-types.js --- a/lib/types/redux-types.js +++ b/lib/types/redux-types.js @@ -33,6 +33,7 @@ import type { LifecycleState } from './lifecycle-state-types'; import type { LoadingStatus, LoadingInfo } from './loading-types'; import type { UpdateMultimediaMessageMediaPayload } from './media-types'; +import type { MessageReportCreationResult } from './message-report-types'; import type { MessageStore, RawMultimediaMessageInfo, @@ -801,6 +802,22 @@ +type: 'SET_USER_SETTINGS_FAILED', +payload: Error, +loadingInfo: LoadingInfo, + } + | { + +type: 'SEND_MESSAGE_REPORT_STARTED', + +payload?: void, + +loadingInfo: LoadingInfo, + } + | { + +type: 'SEND_MESSAGE_REPORT_SUCCESS', + +payload: MessageReportCreationResult, + +loadingInfo: LoadingInfo, + } + | { + +type: 'SEND_MESSAGE_REPORT_FAILED', + +error: true, + +payload: Error, + +loadingInfo: LoadingInfo, }; export type ActionPayload = ?(Object | Array<*> | $ReadOnlyArray<*> | string); diff --git a/native/chat/message-report-utils.js b/native/chat/message-report-utils.js new file mode 100644 --- /dev/null +++ b/native/chat/message-report-utils.js @@ -0,0 +1,68 @@ +// @flow + +import Alert from 'react-native/Libraries/Alert/Alert'; + +import { + sendMessageReport, + sendMessageReportActionTypes, +} from 'lib/actions/message-report-actions'; +import type { BindServerCall, DispatchFunctions } from 'lib/utils/action-utils'; + +import { displayActionResultModal } from '../navigation/action-result-modal'; +import type { TooltipRoute } from '../navigation/tooltip.react'; + +const confirmReport = () => displayActionResultModal('reported to admin'); + +function onPressReport( + route: + | TooltipRoute<'TextMessageTooltipModal'> + | TooltipRoute<'MultimediaMessageTooltipModal'>, + dispatchFunctions: DispatchFunctions, + bindServerCall: BindServerCall, +) { + const messageID = route.params.item.messageInfo.id; + if (!messageID) { + Alert.alert( + 'Couldn’t send the report', + 'Uhh... try again?', + [{ text: 'OK' }], + { + cancelable: false, + }, + ); + return; + } + reportMessage(messageID, dispatchFunctions, bindServerCall); +} + +function reportMessage( + messageID: string, + dispatchFunctions: DispatchFunctions, + bindServerCall: BindServerCall, +) { + const callSendMessageReport = bindServerCall(sendMessageReport); + const messageReportPromise = (async () => { + try { + const result = await callSendMessageReport({ messageID }); + confirmReport(); + return result; + } catch (e) { + Alert.alert( + 'Couldn’t send the report', + 'Uhh... try again?', + [{ text: 'OK' }], + { + cancelable: false, + }, + ); + throw e; + } + })(); + + dispatchFunctions.dispatchActionPromise( + sendMessageReportActionTypes, + messageReportPromise, + ); +} + +export { onPressReport }; diff --git a/native/chat/multimedia-message-tooltip-modal.react.js b/native/chat/multimedia-message-tooltip-modal.react.js --- a/native/chat/multimedia-message-tooltip-modal.react.js +++ b/native/chat/multimedia-message-tooltip-modal.react.js @@ -2,7 +2,6 @@ import * as React from 'react'; -import { displayActionResultModal } from '../navigation/action-result-modal'; import { createTooltip, tooltipHeight, @@ -11,6 +10,7 @@ } from '../navigation/tooltip.react'; import type { ChatMultimediaMessageInfoItem } from '../types/chat-types'; import type { VerticalBounds } from '../types/layout-types'; +import { onPressReport } from './message-report-utils'; import MultimediaMessageTooltipButton from './multimedia-message-tooltip-button.react'; import { navigateToSidebar } from './sidebar-navigation'; @@ -19,7 +19,6 @@ +verticalBounds: VerticalBounds, }>; -const confirmReport = () => displayActionResultModal('reported to admin'); const spec = { entries: [ { @@ -35,7 +34,7 @@ { id: 'report', text: 'Report', - onPress: confirmReport, + onPress: onPressReport, }, ], }; diff --git a/native/chat/text-message-tooltip-modal.react.js b/native/chat/text-message-tooltip-modal.react.js --- a/native/chat/text-message-tooltip-modal.react.js +++ b/native/chat/text-message-tooltip-modal.react.js @@ -17,6 +17,7 @@ type BaseTooltipProps, } from '../navigation/tooltip.react'; import type { ChatTextMessageInfoItemWithHeight } from '../types/chat-types'; +import { onPressReport } from './message-report-utils'; import { navigateToSidebar } from './sidebar-navigation'; import TextMessageTooltipButton from './text-message-tooltip-button.react'; @@ -25,7 +26,6 @@ }>; const confirmCopy = () => displayActionResultModal('copied!'); -const confirmReport = () => displayActionResultModal('reported to admin'); function onPressCopy(route: TooltipRoute<'TextMessageTooltipModal'>) { Clipboard.setString(route.params.item.messageInfo.text); @@ -52,7 +52,7 @@ { id: 'report', text: 'Report', - onPress: confirmReport, + onPress: onPressReport, }, { id: 'create_sidebar',