Skip to content

Commit

Permalink
Merge pull request #22227 from robertKozik/8k
Browse files Browse the repository at this point in the history
#10148 — The message got sent but it also stayed in the compose box
  • Loading branch information
AndrewGable authored Jul 26, 2023
2 parents d227fe3 + 9e4deb5 commit 46fb873
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 18 deletions.
6 changes: 5 additions & 1 deletion src/components/RNTextInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import _ from 'underscore';
// eslint-disable-next-line no-restricted-imports
import {TextInput} from 'react-native';
import Animated from 'react-native-reanimated';
import PropTypes from 'prop-types';

const propTypes = {
Expand All @@ -13,9 +14,12 @@ const defaultProps = {
forwardedRef: () => {},
};

// Convert the underlying TextInput into an Animated component so that we can take an animated ref and pass it to a worklet
const AnimatedTextInput = Animated.createAnimatedComponent(TextInput);

function RNTextInput(props) {
return (
<TextInput
<AnimatedTextInput
allowFontScaling={false}
ref={(ref) => {
if (!_.isFunction(props.forwardedRef)) {
Expand Down
33 changes: 33 additions & 0 deletions src/components/withAnimatedRef.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from 'react';
import {useAnimatedRef} from 'react-native-reanimated';
import PropTypes from 'prop-types';
import getComponentDisplayName from '../libs/getComponentDisplayName';

export default function withAnimatedRef(WrappedComponent) {
function WithAnimatedRef(props) {
const animatedRef = useAnimatedRef();
return (
<WrappedComponent
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
ref={props.forwardedRef}
animatedRef={animatedRef}
/>
);
}
WithAnimatedRef.displayName = `withAnimatedRef(${getComponentDisplayName(WrappedComponent)})`;
WithAnimatedRef.propTypes = {
forwardedRef: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({current: PropTypes.instanceOf(React.Component)})]),
};
WithAnimatedRef.defaultProps = {
forwardedRef: undefined,
};

return React.forwardRef((props, ref) => (
<WithAnimatedRef
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
forwardedRef={ref}
/>
));
}
2 changes: 1 addition & 1 deletion src/components/withNavigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export default function withNavigation(WrappedComponent) {
forwardedRef: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({current: PropTypes.instanceOf(React.Component)})]),
};
WithNavigation.defaultProps = {
forwardedRef: undefined,
forwardedRef: () => {},
};
return React.forwardRef((props, ref) => (
<WithNavigation
Expand Down
3 changes: 3 additions & 0 deletions src/libs/updatePropsPaperWorklet/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function () {
'worklet';
}
7 changes: 7 additions & 0 deletions src/libs/updatePropsPaperWorklet/index.native.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function (viewTag, viewName, updates) {
'worklet';

// _updatePropsPaper is a function that is worklet function from react-native-reanimated which is not available on web
// eslint-disable-next-line no-undef
_updatePropsPaper(viewTag, viewName, updates);
}
64 changes: 48 additions & 16 deletions src/pages/home/report/ReportActionCompose.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React from 'react';
import PropTypes from 'prop-types';
import {View, InteractionManager, LayoutAnimation, NativeModules, findNodeHandle} from 'react-native';
import {runOnJS} from 'react-native-reanimated';
import {Gesture, GestureDetector} from 'react-native-gesture-handler';
import _ from 'underscore';
import lodashGet from 'lodash/get';
import {withOnyx} from 'react-native-onyx';
Expand Down Expand Up @@ -56,6 +58,8 @@ import * as IOU from '../../../libs/actions/IOU';
import PressableWithFeedback from '../../../components/Pressable/PressableWithFeedback';
import * as KeyDownListener from '../../../libs/KeyboardShortcut/KeyDownPressListener';
import * as EmojiPickerActions from '../../../libs/actions/EmojiPickerAction';
import withAnimatedRef from '../../../components/withAnimatedRef';
import updatePropsPaperWorklet from '../../../libs/updatePropsPaperWorklet';

const propTypes = {
/** Beta features list */
Expand Down Expand Up @@ -118,6 +122,9 @@ const propTypes = {
/** The type of action that's pending */
pendingAction: PropTypes.oneOf(['add', 'update', 'delete']),

/** animated ref from react-native-reanimated */
animatedRef: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({current: PropTypes.instanceOf(React.Component)})]).isRequired,

/** Unique id for nativeId in DragAndDrop */
dragAndDropId: PropTypes.string.isRequired,

Expand Down Expand Up @@ -374,6 +381,9 @@ class ReportActionCompose extends React.Component {
setTextInputRef(el) {
ReportActionComposeFocusManager.composerRef.current = el;
this.textInput = el;
if (_.isFunction(this.props.animatedRef)) {
this.props.animatedRef(el);
}
}

/**
Expand Down Expand Up @@ -908,9 +918,9 @@ class ReportActionCompose extends React.Component {
*/
prepareCommentAndResetComposer() {
const trimmedComment = this.comment.trim();

const commentLength = ReportUtils.getCommentLength(trimmedComment);
// Don't submit empty comments or comments that exceed the character limit
if (this.state.isCommentEmpty || ReportUtils.getCommentLength(trimmedComment) > CONST.MAX_COMMENT_LENGTH) {
if (!commentLength || commentLength > CONST.MAX_COMMENT_LENGTH) {
return '';
}

Expand Down Expand Up @@ -984,6 +994,22 @@ class ReportActionCompose extends React.Component {
const isFullComposerAvailable = this.state.isFullComposerAvailable && !_.isEmpty(this.state.value);
const hasReportRecipient = _.isObject(reportRecipient) && !_.isEmpty(reportRecipient);
const maxComposerLines = this.props.isSmallScreenWidth ? CONST.COMPOSER.MAX_LINES_SMALL_SCREEN : CONST.COMPOSER.MAX_LINES;
const submit = this.submitForm;
const animatedRef = this.props.animatedRef;
const setCommentEmpty = () => this.setState({isCommentEmpty: true});
const Tap = Gesture.Tap()
.enabled(!(this.state.isCommentEmpty || isBlockedFromConcierge || this.props.disabled || hasExceededMaxCommentLength))
.onEnd(() => {
'worklet';

const viewTag = animatedRef();
const viewName = 'RCTMultilineTextInputView';
const updates = {text: ''};
// we are setting the isCommentEmpty flag to true so the status of it will be in sync of the native text input state
runOnJS(setCommentEmpty)();
updatePropsPaperWorklet(viewTag, viewName, updates); // clears native text input on the UI thread
runOnJS(submit)();
});

return (
<View
Expand Down Expand Up @@ -1204,20 +1230,25 @@ class ReportActionCompose extends React.Component {
// Keep focus on the composer when Send message is clicked.
onMouseDown={(e) => e.preventDefault()}
>
<Tooltip text={this.props.translate('common.send')}>
<PressableWithFeedback
style={[styles.chatItemSubmitButton, this.state.isCommentEmpty || hasExceededMaxCommentLength ? undefined : styles.buttonSuccess]}
onPress={this.submitForm}
disabled={this.state.isCommentEmpty || isBlockedFromConcierge || this.props.disabled || hasExceededMaxCommentLength}
accessibilityRole={CONST.ACCESSIBILITY_ROLE.BUTTON}
accessibilityLabel={this.props.translate('common.send')}
>
<Icon
src={Expensicons.Send}
fill={this.state.isCommentEmpty || hasExceededMaxCommentLength ? themeColors.icon : themeColors.textLight}
/>
</PressableWithFeedback>
</Tooltip>
<GestureDetector gesture={Tap}>
<Tooltip text={this.props.translate('common.send')}>
<PressableWithFeedback
style={({pressed, isDisabled}) => [
styles.chatItemSubmitButton,
this.state.isCommentEmpty || hasExceededMaxCommentLength || pressed || isDisabled ? undefined : styles.buttonSuccess,
]}
accessibilityRole={CONST.ACCESSIBILITY_ROLE.BUTTON}
accessibilityLabel={this.props.translate('common.send')}
>
{({pressed}) => (
<Icon
src={Expensicons.Send}
fill={this.state.isCommentEmpty || hasExceededMaxCommentLength || pressed ? themeColors.icon : themeColors.textLight}
/>
)}
</PressableWithFeedback>
</Tooltip>
</GestureDetector>
</View>
</View>
<View
Expand Down Expand Up @@ -1300,6 +1331,7 @@ export default compose(
withNetwork(),
withCurrentUserPersonalDetails,
withKeyboardState,
withAnimatedRef,
withOnyx({
betas: {
key: ONYXKEYS.BETAS,
Expand Down

0 comments on commit 46fb873

Please sign in to comment.