mattermost-mobile/app/actions/remote/apps.ts
Daniel Espino García 55324127e1
[Gekidou] Post input (#5844)
* Initial commit post input

* Fix message posting, add create direct channel and minor fixes

* Fix "is typing" and "react to last post" behaviour

* Some reordering, better handling of upload error, properly clear draft on send message, and fix minor progress bar misbehavior

* Add keyboard listener for shift-enter, add selection between video or photo while attaching, add alert when trying to attach more than you are allowed, add paste functionality, minor fixes and reordering

* Add library patch

* Fix lint

* Address feedback

* Address feedback

* Add missing negation

* Check for group name and fix typo on draft comparisons

* Address feedback

* Address feedback

* Address feedback

* Address feedback

* Fix several bugs

* Remove @app imports

* Address feedback

* fix post list & post draft layout on iOS

* Fix post draft cursor position

* Fix file upload route

* Allow to pick multiple images using the image picker

* accurately get the channel member count

* remove android cursor workaround

* Remove local const INPUT_LINE_HEIGHT

* move getPlaceHolder out of the component

* use substring instead of legacy substr for hardward keyboard

* Move onAppStateChange above the effects

* Fix camera action bottom sheet

* no need to memo SendButton

* properly use memberCount in sender handler

* Refactor how to get memberCount

* Fix queryRecentPostsInThread

* Remove unused isDirectChannelVisible && isGroupChannelVisible util functions

* rename errorBadUser to errorUnkownUser

* extract localized strings

* use ClientErrorProps instead of ClientError

* Minor improvements

Co-authored-by: Elias Nahum <nahumhbl@gmail.com>
2022-02-03 08:59:15 -03:00

164 lines
5.9 KiB
TypeScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {IntlShape} from 'react-intl';
import {sendEphemeralPost} from '@actions/local/post';
import CompassIcon from '@components/compass_icon';
import {Screens} from '@constants';
import {AppCallResponseTypes, AppCallTypes} from '@constants/apps';
import NetworkManager from '@init/network_manager';
import {showModal} from '@screens/navigation';
import EphemeralStore from '@store/ephemeral_store';
import {makeCallErrorResponse} from '@utils/apps';
import type {Client} from '@client/rest';
import type PostModel from '@typings/database/models/servers/post';
export async function doAppCall<Res=unknown>(serverUrl: string, call: AppCallRequest, type: AppCallType, intl: IntlShape, theme: Theme) {
let client: Client;
try {
client = NetworkManager.getClient(serverUrl);
} catch (error) {
return {error};
}
try {
const res = await client.executeAppCall(call, type) as AppCallResponse<Res>;
const responseType = res.type || AppCallResponseTypes.OK;
switch (responseType) {
case AppCallResponseTypes.OK:
return {data: res};
case AppCallResponseTypes.ERROR:
return {error: res};
case AppCallResponseTypes.FORM: {
if (!res.form) {
const errMsg = intl.formatMessage({
id: 'apps.error.responses.form.no_form',
defaultMessage: 'Response type is `form`, but no form was included in the response.',
});
return {error: makeCallErrorResponse(errMsg)};
}
const screen = EphemeralStore.getNavigationTopComponentId();
if (type === AppCallTypes.SUBMIT && screen !== Screens.APP_FORM) {
showAppForm(res.form, call, theme);
}
return {data: res};
}
case AppCallResponseTypes.NAVIGATE:
if (!res.navigate_to_url) {
const errMsg = intl.formatMessage({
id: 'apps.error.responses.navigate.no_url',
defaultMessage: 'Response type is `navigate`, but no url was included in response.',
});
return {error: makeCallErrorResponse(errMsg)};
}
if (type !== AppCallTypes.SUBMIT) {
const errMsg = intl.formatMessage({
id: 'apps.error.responses.navigate.no_submit',
defaultMessage: 'Response type is `navigate`, but the call was not a submission.',
});
return {error: makeCallErrorResponse(errMsg)};
}
// TODO: Add functionality to handle this
// handleGotoLocation(res.navigate_to_url, intl);
return {data: res};
default: {
const errMsg = intl.formatMessage({
id: 'apps.error.responses.unknown_type',
defaultMessage: 'App response type not supported. Response type: {type}.',
}, {
type: responseType,
});
return {error: makeCallErrorResponse(errMsg)};
}
}
} catch (error) {
const errMsg = (error as Error).message || intl.formatMessage({
id: 'apps.error.responses.unexpected_error',
defaultMessage: 'Received an unexpected error.',
});
return {error: makeCallErrorResponse(errMsg)};
}
}
export function postEphemeralCallResponseForPost(serverUrl: string, response: AppCallResponse, message: string, post: PostModel) {
return sendEphemeralPost(
serverUrl,
message,
post.channelId,
post.rootId,
response.app_metadata?.bot_user_id,
);
}
export function postEphemeralCallResponseForChannel(serverUrl: string, response: AppCallResponse, message: string, channelID: string) {
return sendEphemeralPost(
serverUrl,
message,
channelID,
'',
response.app_metadata?.bot_user_id,
);
}
export function postEphemeralCallResponseForContext(serverUrl: string, response: AppCallResponse, message: string, context: AppContext) {
return sendEphemeralPost(
serverUrl,
message,
context.channel_id!,
context.root_id || context.post_id,
response.app_metadata?.bot_user_id,
);
}
export function postEphemeralCallResponseForCommandArgs(serverUrl: string, response: AppCallResponse, message: string, args: CommandArgs) {
return sendEphemeralPost(
serverUrl,
message,
args.channel_id,
args.root_id,
response.app_metadata?.bot_user_id,
);
}
export const showAppForm = async (form: AppForm, call: AppCallRequest, theme: Theme) => {
const closeButton = await CompassIcon.getImageSource('close', 24, theme.sidebarHeaderTextColor);
let submitButtons = [{
id: 'submit-form',
showAsAction: 'always',
text: 'Submit',
}];
if (form.submit_buttons) {
const options = form.fields.find((f) => f.name === form.submit_buttons)?.options;
const newButtons = options?.map((o) => {
return {
id: 'submit-form_' + o.value,
showAsAction: 'always',
text: o.label,
};
});
if (newButtons && newButtons.length > 0) {
submitButtons = newButtons;
}
}
const options = {
topBar: {
leftButtons: [{
id: 'close-dialog',
icon: closeButton,
}],
rightButtons: submitButtons,
},
};
const passProps = {form, call};
showModal(Screens.APP_FORM, form.title || '', passProps, options);
};