Skip to content

Commit

Permalink
Merge pull request Expensify#25758 from margelo/refactor-report-actio…
Browse files Browse the repository at this point in the history
…n-compose

Performance: chat input
  • Loading branch information
mountiny authored Aug 25, 2023
2 parents 68a9fcd + e64a5d9 commit 0acef6d
Show file tree
Hide file tree
Showing 21 changed files with 2,468 additions and 1,423 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import PropTypes from 'prop-types';
import refPropType from '../refPropTypes';

const propTypes = {
/** Array of suggestions */
Expand Down Expand Up @@ -29,16 +28,12 @@ const propTypes = {
/** create accessibility label for each item */
accessibilityLabelExtractor: PropTypes.func.isRequired,

/** Ref of the container enclosing the menu.
* This is needed to render the menu in correct position inside a portal
*/
parentContainerRef: refPropType,
/** Meaures the parent container's position and dimensions. */
measureParentContainer: PropTypes.func,
};

const defaultProps = {
parentContainerRef: {
current: null,
},
measureParentContainer: () => {},
};

export {propTypes, defaultProps};
14 changes: 7 additions & 7 deletions src/components/EmojiSuggestions.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import * as EmojiUtils from '../libs/EmojiUtils';
import Text from './Text';
import getStyledTextArray from '../libs/GetStyledTextArray';
import AutoCompleteSuggestions from './AutoCompleteSuggestions';
import refPropType from './refPropTypes';

const propTypes = {
/** The index of the highlighted emoji */
Expand Down Expand Up @@ -47,13 +46,14 @@ const propTypes = {
/** Stores user's preferred skin tone */
preferredSkinToneIndex: PropTypes.number.isRequired,

/** Ref of the container enclosing the menu.
* This is needed to render the menu in correct position inside a portal
*/
containerRef: refPropType,
/** Meaures the parent container's position and dimensions. */
measureParentContainer: PropTypes.func,
};

const defaultProps = {highlightedEmojiIndex: 0, containerRef: {current: null}};
const defaultProps = {
highlightedEmojiIndex: 0,
measureParentContainer: () => {},
};

/**
* Create unique keys for each emoji item
Expand Down Expand Up @@ -104,7 +104,7 @@ function EmojiSuggestions(props) {
isSuggestionPickerLarge={props.isEmojiPickerLarge}
shouldIncludeReportRecipientLocalTimeHeight={props.shouldIncludeReportRecipientLocalTimeHeight}
accessibilityLabelExtractor={keyExtractor}
parentContainerRef={props.containerRef}
measureParentContainer={props.measureParentContainer}
/>
);
}
Expand Down
22 changes: 19 additions & 3 deletions src/components/ExceededCommentLength.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
import React, {useEffect, useState, useMemo} from 'react';
import PropTypes from 'prop-types';
import {debounce} from 'lodash';
import {withOnyx} from 'react-native-onyx';
import CONST from '../CONST';
import * as ReportUtils from '../libs/ReportUtils';
import Text from './Text';
import styles from '../styles/styles';
import ONYXKEYS from '../ONYXKEYS';

const propTypes = {
/** Report ID to get the comment from (used in withOnyx) */
// eslint-disable-next-line react/no-unused-prop-types
reportID: PropTypes.string.isRequired,

/** Text Comment */
comment: PropTypes.string.isRequired,
comment: PropTypes.string,

/** Update UI on parent when comment length is exceeded */
onExceededMaxCommentLength: PropTypes.func.isRequired,
};

const defaultProps = {
comment: '',
};

function ExceededCommentLength(props) {
const [commentLength, setCommentLength] = useState(0);
const updateCommentLength = useMemo(
Expand All @@ -38,5 +48,11 @@ function ExceededCommentLength(props) {
}

ExceededCommentLength.propTypes = propTypes;

export default ExceededCommentLength;
ExceededCommentLength.defaultProps = defaultProps;
ExceededCommentLength.displayName = 'ExceededCommentLength';

export default withOnyx({
comment: {
key: ({reportID}) => `${ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT}${reportID}`,
},
})(ExceededCommentLength);
13 changes: 4 additions & 9 deletions src/components/MentionSuggestions.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import Avatar from './Avatar';
import AutoCompleteSuggestions from './AutoCompleteSuggestions';
import getStyledTextArray from '../libs/GetStyledTextArray';
import avatarPropTypes from './avatarPropTypes';
import refPropType from './refPropTypes';

const propTypes = {
/** The index of the highlighted mention */
Expand Down Expand Up @@ -44,17 +43,13 @@ const propTypes = {
/** Show that we should include ReportRecipientLocalTime view height */
shouldIncludeReportRecipientLocalTimeHeight: PropTypes.bool.isRequired,

/** Ref of the container enclosing the menu.
* This is needed to render the menu in correct position inside a portal
*/
containerRef: refPropType,
/** Meaures the parent container's position and dimensions. */
measureParentContainer: PropTypes.func,
};

const defaultProps = {
highlightedMentionIndex: 0,
containerRef: {
current: null,
},
measureParentContainer: () => {},
};

/**
Expand Down Expand Up @@ -131,7 +126,7 @@ function MentionSuggestions(props) {
isSuggestionPickerLarge={props.isMentionPickerLarge}
shouldIncludeReportRecipientLocalTimeHeight={props.shouldIncludeReportRecipientLocalTimeHeight}
accessibilityLabelExtractor={keyExtractor}
parentContainerRef={props.containerRef}
measureParentContainer={props.measureParentContainer}
/>
);
}
Expand Down
13 changes: 13 additions & 0 deletions src/libs/ComposerUtils/debouncedSaveReportComment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import _ from 'underscore';
import * as Report from '../actions/Report';

/**
* Save draft report comment. Debounced to happen at most once per second.
* @param {String} reportID
* @param {String} comment
*/
const debouncedSaveReportComment = _.debounce((reportID, comment) => {
Report.saveReportComment(reportID, comment || '');
}, 1000);

export default debouncedSaveReportComment;
24 changes: 24 additions & 0 deletions src/libs/ComposerUtils/getDraftComment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import Onyx from 'react-native-onyx';
import ONYXKEYS from '../../ONYXKEYS';

const draftCommentMap = {};
Onyx.connect({
key: ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT,
callback: (value, key) => {
if (!key) return;

const reportID = key.replace(ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT, '');
draftCommentMap[reportID] = value;
},
});

/**
* Returns a draft comment from the onyx collection.
* Note: You should use the HOCs/hooks to get onyx data, instead of using this directly.
* A valid use case to use this is if the value is only needed once for an initial value.
* @param {String} reportID
* @returns {String|undefined}
*/
export default function getDraftComment(reportID) {
return draftCommentMap[reportID];
}
29 changes: 29 additions & 0 deletions src/libs/SuggestionUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import CONST from '../CONST';

/**
* Return the max available index for arrow manager.
* @param {Number} numRows
* @param {Boolean} isAutoSuggestionPickerLarge
* @returns {Number}
*/
function getMaxArrowIndex(numRows, isAutoSuggestionPickerLarge) {
// rowCount is number of emoji/mention suggestions. For small screen we can fit 3 items
// and for large we show up to 20 items for mentions/emojis
const rowCount = isAutoSuggestionPickerLarge
? Math.min(numRows, CONST.AUTO_COMPLETE_SUGGESTER.MAX_AMOUNT_OF_SUGGESTIONS)
: Math.min(numRows, CONST.AUTO_COMPLETE_SUGGESTER.MIN_AMOUNT_OF_SUGGESTIONS);

// -1 because we start at 0
return rowCount - 1;
}

/**
* Trims first character of the string if it is a space
* @param {String} str
* @returns {String}
*/
function trimLeadingSpace(str) {
return str.slice(0, 1) === ' ' ? str.slice(1) : str;
}

export {getMaxArrowIndex, trimLeadingSpace};
21 changes: 21 additions & 0 deletions src/libs/getModalState.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import Onyx from 'react-native-onyx';
import ONYXKEYS from '../ONYXKEYS';

let modalState = {};

Onyx.connect({
key: ONYXKEYS.MODAL,
callback: (val) => {
modalState = val;
},
});

/**
* Returns the modal state from onyx.
* Note: You should use the HOCs/hooks to get onyx data, instead of using this directly.
* A valid use case to use this is if the value is only needed once for an initial value.
* @returns {Object}
*/
export default function getModalState() {
return modalState;
}
Loading

0 comments on commit 0acef6d

Please sign in to comment.