From fc9aec95d3aa72053998ed244b2432ff178f8aa1 Mon Sep 17 00:00:00 2001 From: Alberto Date: Wed, 15 Mar 2023 13:06:43 -0400 Subject: [PATCH 001/751] changing branchs --- .../home/report/ContextMenu/ContextMenuActions.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index cab49dcc3c9c..a7762103cfe8 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -34,6 +34,7 @@ const CONTEXT_MENU_TYPES = { LINK: 'LINK', REPORT_ACTION: 'REPORT_ACTION', EMAIL: 'EMAIL', + EMAIL: '', }; // A list of all the context actions in this menu. @@ -254,6 +255,18 @@ export default [ }, getDescription: () => {}, }, + { + textTranslateKey: 'reportActionContextMenu.markAsUnread', + icon: Expensicons.Pin, + shouldShow: type => type === CONTEXT_MENU_TYPES.REPORT_ACTION, + onPress: (closePopover, {reportAction, reportID}) => { + Report.markCommentAsUnread(reportID, reportAction.created); + if (closePopover) { + hideContextMenu(true, ReportActionComposeFocusManager.focus); + } + }, + getDescription: () => {}, + }, ]; export { From 24381ed092b0ec280083b9454fd6968710e552fd Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Thu, 16 Mar 2023 10:34:31 -0700 Subject: [PATCH 002/751] refactor tooltip to fix double focusable component --- .../BaseAnchorForCommentsOnly.js | 2 +- src/components/AvatarWithIndicator.js | 8 +- src/components/DisplayNames/index.js | 1 - .../EmojiPicker/CategoryShortcutButton.js | 29 +++-- src/components/FloatingActionButton.js | 2 +- src/components/Hoverable/index.js | 103 ++++++++---------- src/components/MultipleAvatars.js | 14 +-- src/components/OptionRow.js | 6 +- src/components/Reactions/AddReactionBubble.js | 2 +- .../BaseQuickEmojiReactions.js | 4 +- src/components/ReportWelcomeText.js | 2 +- src/components/SubscriptAvatar.js | 32 +++--- src/components/Tooltip/index.js | 72 ++++++------ .../home/report/ReportActionItemSingle.js | 18 +-- src/pages/settings/InitialSettingsPage.js | 9 +- src/pages/signin/SignInPageLayout/Footer.js | 15 ++- src/pages/workspace/WorkspaceInitialPage.js | 16 +-- src/stories/Tooltip.stories.js | 1 - 18 files changed, 160 insertions(+), 176 deletions(-) diff --git a/src/components/AnchorForCommentsOnly/BaseAnchorForCommentsOnly.js b/src/components/AnchorForCommentsOnly/BaseAnchorForCommentsOnly.js index 18d3fbf25960..22a4ce75f99c 100644 --- a/src/components/AnchorForCommentsOnly/BaseAnchorForCommentsOnly.js +++ b/src/components/AnchorForCommentsOnly/BaseAnchorForCommentsOnly.js @@ -65,7 +65,7 @@ const BaseAnchorForCommentsOnly = (props) => { onPressIn={props.onPressIn} onPressOut={props.onPressOut} > - + linkRef = el} style={StyleSheet.flatten([props.style, defaultTextStyle])} diff --git a/src/components/AvatarWithIndicator.js b/src/components/AvatarWithIndicator.js index 6430d463a712..9bae6d9488c6 100644 --- a/src/components/AvatarWithIndicator.js +++ b/src/components/AvatarWithIndicator.js @@ -85,8 +85,8 @@ const AvatarWithIndicator = (props) => { const shouldShowIndicator = _.some(errorCheckingMethods, errorCheckingMethod => errorCheckingMethod()); return ( - - + + { {shouldShowIndicator && ( )} - - + + ); }; diff --git a/src/components/DisplayNames/index.js b/src/components/DisplayNames/index.js index fd23a011bf69..83def9ce8c05 100644 --- a/src/components/DisplayNames/index.js +++ b/src/components/DisplayNames/index.js @@ -95,7 +95,6 @@ class DisplayNames extends PureComponent { this.getTooltipShiftX(index)} > {/* // We need to get the refs to all the names which will be used to correct diff --git a/src/components/EmojiPicker/CategoryShortcutButton.js b/src/components/EmojiPicker/CategoryShortcutButton.js index 2c5f061327ae..33d5576c29ea 100644 --- a/src/components/EmojiPicker/CategoryShortcutButton.js +++ b/src/components/EmojiPicker/CategoryShortcutButton.js @@ -33,20 +33,19 @@ class CategoryShortcutButton extends PureComponent { render() { return ( - this.setState({isHighlighted: true})} - onHoverOut={() => this.setState({isHighlighted: false})} - style={({pressed}) => ([ - StyleUtils.getButtonBackgroundColorStyle(getButtonState(false, pressed)), - styles.categoryShortcutButton, - this.state.isHighlighted && styles.emojiItemHighlighted, - ])} + - this.setState({isHighlighted: true})} + onHoverOut={() => this.setState({isHighlighted: false})} + style={({pressed}) => ([ + StyleUtils.getButtonBackgroundColorStyle(getButtonState(false, pressed)), + styles.categoryShortcutButton, + this.state.isHighlighted && styles.emojiItemHighlighted, + ])} > - - + + ); } } diff --git a/src/components/FloatingActionButton.js b/src/components/FloatingActionButton.js index 2bc1d96d05ec..13275e5116a3 100644 --- a/src/components/FloatingActionButton.js +++ b/src/components/FloatingActionButton.js @@ -73,7 +73,7 @@ class FloatingActionButton extends PureComponent { }); return ( - + this.fabPressable = el} diff --git a/src/components/Hoverable/index.js b/src/components/Hoverable/index.js index 2f10cca0c1e3..2f275dd968fe 100644 --- a/src/components/Hoverable/index.js +++ b/src/components/Hoverable/index.js @@ -55,68 +55,55 @@ class Hoverable extends Component { } render() { - if (this.props.absolute && React.isValidElement(this.props.children)) { - return React.cloneElement(React.Children.only(this.props.children), { - ref: (el) => { - this.wrapperView = el; - - // Call the original ref, if any - const {ref} = this.props.children; - if (_.isFunction(ref)) { - ref(el); - } - }, - onMouseEnter: (el) => { - this.setIsHovered(true); - - // Call the original onMouseEnter, if any - const {onMouseEnter} = this.props.children; - if (_.isFunction(onMouseEnter)) { - onMouseEnter(el); - } - }, - onMouseLeave: (el) => { - this.setIsHovered(false); + const child = _.isFunction(this.props.children) + ? this.props.children(this.state.isHovered) + : this.props.children - // Call the original onMouseLeave, if any - const {onMouseLeave} = this.props.children; - if (_.isFunction(onMouseLeave)) { - onMouseLeave(el); - } - }, - onBlur: (el) => { - if (!this.wrapperView.contains(el.relatedTarget)) { - this.setIsHovered(false); - } - - // Call the original onBlur, if any - const {onBlur} = this.props.children; - if (_.isFunction(onBlur)) { - onBlur(el); - } - }, - }); + if (!React.isValidElement(child)) { + throw Error("Children is not a valid element."); } - return ( - this.wrapperView = el} - onMouseEnter={() => this.setIsHovered(true)} - onMouseLeave={() => this.setIsHovered(false)} - onBlur={(el) => { - if (this.wrapperView.contains(el.relatedTarget)) { - return; - } + + return React.cloneElement(React.Children.only(child), { + ref: (el) => { + this.wrapperView = el; + + // Call the original ref, if any + const {ref} = child; + if (_.isFunction(ref)) { + ref(el); + } + }, + onMouseEnter: (el) => { + console.log("ENTER") + this.setIsHovered(true); + + // Call the original onMouseEnter, if any + const {onMouseEnter} = child; + if (_.isFunction(onMouseEnter)) { + onMouseEnter(el); + } + }, + onMouseLeave: (el) => { + this.setIsHovered(false); + + // Call the original onMouseLeave, if any + const {onMouseLeave} = child; + if (_.isFunction(onMouseLeave)) { + onMouseLeave(el); + } + }, + onBlur: (el) => { + if (!this.wrapperView.contains(el.relatedTarget)) { this.setIsHovered(false); - }} - > - { // If this.props.children is a function, call it to provide the hover state to the children. - _.isFunction(this.props.children) - ? this.props.children(this.state.isHovered) - : this.props.children } - - ); + + // Call the original onBlur, if any + const {onBlur} = child; + if (_.isFunction(onBlur)) { + onBlur(el); + } + }, + }); } } diff --git a/src/components/MultipleAvatars.js b/src/components/MultipleAvatars.js index 6e30a2579a25..9a5099483fcc 100644 --- a/src/components/MultipleAvatars.js +++ b/src/components/MultipleAvatars.js @@ -69,8 +69,8 @@ const MultipleAvatars = (props) => { if (props.icons.length === 1 && !props.shouldStackHorizontally) { return ( - - + + { name={props.icons[0].name} type={props.icons[0].type} /> - - + + ); } @@ -127,7 +127,7 @@ const MultipleAvatars = (props) => { - + {/* View is necessary for tooltip to show for multiple avatars in LHN */} { style={secondAvatarStyles} > {props.icons.length === 2 ? ( - + { ) : ( - + diff --git a/src/components/OptionRow.js b/src/components/OptionRow.js index 532ae783bdd6..1bf7219df9d2 100644 --- a/src/components/OptionRow.js +++ b/src/components/OptionRow.js @@ -149,11 +149,7 @@ class OptionRow extends Component { errors={this.props.option.allReportErrors} shouldShowErrorMessages={false} > - + {hovered => ( touchableRef = el} diff --git a/src/components/Reactions/AddReactionBubble.js b/src/components/Reactions/AddReactionBubble.js index 3b57771311ab..0eb40ecccdc7 100644 --- a/src/components/Reactions/AddReactionBubble.js +++ b/src/components/Reactions/AddReactionBubble.js @@ -79,7 +79,7 @@ const AddReactionBubble = (props) => { }; return ( - + ( {_.map(CONST.QUICK_REACTIONS, emoji => ( - - // Note: focus is handled by the Pressable component in EmojiReactionBubble - + { displayName, pronouns, tooltip, }, index) => ( - + Navigation.navigate(ROUTES.getDetailsRoute(participants[index]))}> {displayName} diff --git a/src/components/SubscriptAvatar.js b/src/components/SubscriptAvatar.js index 6da3e918fec4..44b3eb723671 100644 --- a/src/components/SubscriptAvatar.js +++ b/src/components/SubscriptAvatar.js @@ -42,20 +42,22 @@ const defaultProps = { const SubscriptAvatar = props => ( - + + + - - + + ( name={props.secondaryAvatar.name} type={props.secondaryAvatar.type} /> - - + + ); diff --git a/src/components/Tooltip/index.js b/src/components/Tooltip/index.js index 104098b375f0..cb4c8b676759 100644 --- a/src/components/Tooltip/index.js +++ b/src/components/Tooltip/index.js @@ -1,6 +1,6 @@ import _ from 'underscore'; import React, {PureComponent} from 'react'; -import {Animated, View} from 'react-native'; +import {Animated} from 'react-native'; import TooltipRenderedOnPageBody from './TooltipRenderedOnPageBody'; import Hoverable from '../Hoverable'; import withWindowDimensions from '../withWindowDimensions'; @@ -37,6 +37,7 @@ class Tooltip extends PureComponent { this.getWrapperPosition = this.getWrapperPosition.bind(this); this.showTooltip = this.showTooltip.bind(this); this.hideTooltip = this.hideTooltip.bind(this); + this.isFocusable = this.isFocusable.bind(this); } componentDidUpdate(prevProps) { @@ -141,47 +142,50 @@ class Tooltip extends PureComponent { TooltipSense.deactivate(); } + /** + * Returns true if children is a focusable component. + * + * @returns {Boolean} + */ + isFocusable() { + const name = this.props.children.type.displayName; + const isPressableText = name === 'Text' && Boolean(this.props.children.props.onPress); + return isPressableText || ['TouchableOpacity', 'Pressable', 'TouchableWithoutFeedback'].includes(name); + } + render() { // Skip the tooltip and return the children if the text is empty, // we don't have a render function or the device does not support hovering if ((_.isEmpty(this.props.text) && this.props.renderTooltipContent == null) || !this.hasHoverSupport) { return this.props.children; } - let child = ( - this.wrapperView = el} - onBlur={this.hideTooltip} - focusable={this.props.focusable} - style={this.props.containerStyles} - > - {this.props.children} - - ); - - if (this.props.absolute && React.isValidElement(this.props.children)) { - child = React.cloneElement(React.Children.only(this.props.children), { - ref: (el) => { - this.wrapperView = el; - // Call the original ref, if any - const {ref} = this.props.children; - if (_.isFunction(ref)) { - ref(el); - } - }, - onBlur: (el) => { - this.hideTooltip(); - - // Call the original onBlur, if any - const {onBlur} = this.props.children; - if (_.isFunction(onBlur)) { - onBlur(el); - } - }, - focusable: true, - }); + if (!React.isValidElement(this.props.children)) { + throw Error("Children is not a valid element."); } + const child = React.cloneElement(React.Children.only(this.props.children), { + ref: (el) => { + this.wrapperView = el; + + // Call the original ref, if any + const {ref} = this.props.children; + if (_.isFunction(ref)) { + ref(el); + } + }, + onBlur: (el) => { + this.hideTooltip(); + + // Call the original onBlur, if any + const {onBlur} = this.props.children; + if (_.isFunction(onBlur)) { + onBlur(el); + } + }, + focusable: this.isFocusable(), + }); + return ( <> {this.state.isRendered && ( @@ -201,8 +205,6 @@ class Tooltip extends PureComponent { /> )} diff --git a/src/pages/home/report/ReportActionItemSingle.js b/src/pages/home/report/ReportActionItemSingle.js index 19d2cc05f58c..d6f5207e5a91 100644 --- a/src/pages/home/report/ReportActionItemSingle.js +++ b/src/pages/home/report/ReportActionItemSingle.js @@ -70,13 +70,13 @@ const ReportActionItemSingle = (props) => { return ( - showUserDetails(actorEmail)} - > - + + showUserDetails(actorEmail)} + > @@ -85,8 +85,8 @@ const ReportActionItemSingle = (props) => { source={avatarSource} /> - - + + {props.showHeader ? ( diff --git a/src/pages/settings/InitialSettingsPage.js b/src/pages/settings/InitialSettingsPage.js index 6d6db5a498f3..16cae58efe31 100755 --- a/src/pages/settings/InitialSettingsPage.js +++ b/src/pages/settings/InitialSettingsPage.js @@ -258,8 +258,8 @@ class InitialSettingsPage extends React.Component { - - + + @@ -269,9 +269,8 @@ class InitialSettingsPage extends React.Component { size={CONST.AVATAR_SIZE.LARGE} /> - - - + + diff --git a/src/pages/signin/SignInPageLayout/Footer.js b/src/pages/signin/SignInPageLayout/Footer.js index 0f6e099bc8c0..2b0f9cd7cf60 100644 --- a/src/pages/signin/SignInPageLayout/Footer.js +++ b/src/pages/signin/SignInPageLayout/Footer.js @@ -162,12 +162,15 @@ const Footer = (props) => { key={row.translationPath} > {hovered => ( - - {props.translate(row.translationPath)} - + + + {console.log(hovered)} + {props.translate(row.translationPath)} + + )} ))} diff --git a/src/pages/workspace/WorkspaceInitialPage.js b/src/pages/workspace/WorkspaceInitialPage.js index fea68a5af262..f4c071457e11 100644 --- a/src/pages/workspace/WorkspaceInitialPage.js +++ b/src/pages/workspace/WorkspaceInitialPage.js @@ -187,12 +187,12 @@ class WorkspaceInitialPage extends React.Component { - - + + - - + + {!_.isEmpty(this.props.policy.name) && ( { From bd13ee31669132ce80e7a3f77fe49bff209d9f2e Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Thu, 16 Mar 2023 10:47:32 -0700 Subject: [PATCH 003/751] remove console log --- src/components/Hoverable/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/Hoverable/index.js b/src/components/Hoverable/index.js index 2f275dd968fe..40574e863e92 100644 --- a/src/components/Hoverable/index.js +++ b/src/components/Hoverable/index.js @@ -74,7 +74,6 @@ class Hoverable extends Component { } }, onMouseEnter: (el) => { - console.log("ENTER") this.setIsHovered(true); // Call the original onMouseEnter, if any From 79031f1d341db711f2eee8df30beb7402b7460a3 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Thu, 16 Mar 2023 10:50:58 -0700 Subject: [PATCH 004/751] fix lint --- src/components/Hoverable/index.js | 5 ++--- src/components/Tooltip/index.js | 2 +- src/pages/signin/SignInPageLayout/Footer.js | 1 - 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/components/Hoverable/index.js b/src/components/Hoverable/index.js index 40574e863e92..7eed07748ed1 100644 --- a/src/components/Hoverable/index.js +++ b/src/components/Hoverable/index.js @@ -1,6 +1,5 @@ import _ from 'underscore'; import React, {Component} from 'react'; -import {View} from 'react-native'; import {propTypes, defaultProps} from './hoverablePropTypes'; /** @@ -57,10 +56,10 @@ class Hoverable extends Component { render() { const child = _.isFunction(this.props.children) ? this.props.children(this.state.isHovered) - : this.props.children + : this.props.children; if (!React.isValidElement(child)) { - throw Error("Children is not a valid element."); + throw Error('Children is not a valid element.'); } return React.cloneElement(React.Children.only(child), { diff --git a/src/components/Tooltip/index.js b/src/components/Tooltip/index.js index cb4c8b676759..b3c555db5da0 100644 --- a/src/components/Tooltip/index.js +++ b/src/components/Tooltip/index.js @@ -161,7 +161,7 @@ class Tooltip extends PureComponent { } if (!React.isValidElement(this.props.children)) { - throw Error("Children is not a valid element."); + throw Error('Children is not a valid element.'); } const child = React.cloneElement(React.Children.only(this.props.children), { diff --git a/src/pages/signin/SignInPageLayout/Footer.js b/src/pages/signin/SignInPageLayout/Footer.js index 2b0f9cd7cf60..3e522b0ce315 100644 --- a/src/pages/signin/SignInPageLayout/Footer.js +++ b/src/pages/signin/SignInPageLayout/Footer.js @@ -167,7 +167,6 @@ const Footer = (props) => { style={[styles.footerRow, hovered ? styles.textBlue : {}]} href={row.link} > - {console.log(hovered)} {props.translate(row.translationPath)} From 1d72fc3055f7df79311fdfd3fc18c4352148c61f Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Thu, 16 Mar 2023 10:52:32 -0700 Subject: [PATCH 005/751] remove absolute prop --- src/components/Tooltip/tooltipPropTypes.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/components/Tooltip/tooltipPropTypes.js b/src/components/Tooltip/tooltipPropTypes.js index 014bdc3354b2..0bdf43971c00 100644 --- a/src/components/Tooltip/tooltipPropTypes.js +++ b/src/components/Tooltip/tooltipPropTypes.js @@ -4,9 +4,6 @@ import variables from '../../styles/variables'; import CONST from '../../CONST'; const propTypes = { - /** Enable support for the absolute positioned native(View|Text) children. It will only work for single native child */ - absolute: PropTypes.bool, - /** The text to display in the tooltip. */ text: PropTypes.string, @@ -41,7 +38,6 @@ const propTypes = { }; const defaultProps = { - absolute: false, shiftHorizontal: 0, shiftVertical: 0, containerStyles: [], From 0f7ed5451e4a067beb3848c347838ea574aa701e Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Thu, 16 Mar 2023 10:52:54 -0700 Subject: [PATCH 006/751] remove focusable prop --- src/components/Tooltip/tooltipPropTypes.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/components/Tooltip/tooltipPropTypes.js b/src/components/Tooltip/tooltipPropTypes.js index 0bdf43971c00..2802bb18ec11 100644 --- a/src/components/Tooltip/tooltipPropTypes.js +++ b/src/components/Tooltip/tooltipPropTypes.js @@ -30,9 +30,6 @@ const propTypes = { /** Number of pixels to set max-width on tooltip */ maxWidth: PropTypes.number, - /** Accessibility prop. Sets the tabindex to 0 if true. Default is true. */ - focusable: PropTypes.bool, - /** Render custom content inside the tooltip. Note: This cannot be used together with the text props. */ renderTooltipContent: PropTypes.func, }; @@ -45,7 +42,6 @@ const defaultProps = { maxWidth: variables.sideBarWidth, numberOfLines: CONST.TOOLTIP_MAX_LINES, renderTooltipContent: undefined, - focusable: true, }; export { From ffaf634cf0f6e51648c8381fa1987511b41df555 Mon Sep 17 00:00:00 2001 From: Alberto Date: Thu, 16 Mar 2023 14:54:43 -0400 Subject: [PATCH 007/751] add PIN action --- .../home/report/ContextMenu/ContextMenuActions.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index a7762103cfe8..43e8f76f0df1 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -19,6 +19,7 @@ import * as Environment from '../../../../libs/Environment/Environment'; import Permissions from '../../../../libs/Permissions'; import QuickEmojiReactions from '../../../../components/Reactions/QuickEmojiReactions'; import MiniQuickEmojiReactions from '../../../../components/Reactions/MiniQuickEmojiReactions'; +import {togglePinnedState} from "../../../../libs/actions/Report"; /** * Gets the HTML version of the message in an action. @@ -34,7 +35,7 @@ const CONTEXT_MENU_TYPES = { LINK: 'LINK', REPORT_ACTION: 'REPORT_ACTION', EMAIL: 'EMAIL', - EMAIL: '', + REPORT: 'REPORT', }; // A list of all the context actions in this menu. @@ -256,11 +257,11 @@ export default [ getDescription: () => {}, }, { - textTranslateKey: 'reportActionContextMenu.markAsUnread', + textTranslateKey: 'pin', icon: Expensicons.Pin, - shouldShow: type => type === CONTEXT_MENU_TYPES.REPORT_ACTION, - onPress: (closePopover, {reportAction, reportID}) => { - Report.markCommentAsUnread(reportID, reportAction.created); + shouldShow: type => type === CONTEXT_MENU_TYPES.REPORT, + onPress: (closePopover, {report}) => { + Report.togglePinnedState(report); if (closePopover) { hideContextMenu(true, ReportActionComposeFocusManager.focus); } From 8789f75a15bbceede31554d9b4102f292069aa8c Mon Sep 17 00:00:00 2001 From: Alberto Date: Fri, 17 Mar 2023 10:19:39 -0400 Subject: [PATCH 008/751] correctly show menu --- src/components/LHNOptionsList/OptionRowLHN.js | 35 +++++++++++++++++++ .../report/ContextMenu/ContextMenuActions.js | 6 ++-- .../ContextMenu/ReportActionContextMenu.js | 2 +- 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/components/LHNOptionsList/OptionRowLHN.js b/src/components/LHNOptionsList/OptionRowLHN.js index c57d51d29eb2..43c60b68f950 100644 --- a/src/components/LHNOptionsList/OptionRowLHN.js +++ b/src/components/LHNOptionsList/OptionRowLHN.js @@ -24,6 +24,13 @@ import themeColors from '../../styles/themes/default'; import SidebarUtils from '../../libs/SidebarUtils'; import TextPill from '../TextPill'; import OfflineWithFeedback from '../OfflineWithFeedback'; +import * as DeviceCapabilities from "../../libs/DeviceCapabilities"; +import ControlSelection from "../../libs/ControlSelection"; +import PressableWithSecondaryInteraction from "../PressableWithSecondaryInteraction"; +import SelectionScraper from "../../libs/SelectionScraper"; +import * as ReportActionContextMenu from "../../pages/home/report/ContextMenu/ReportActionContextMenu"; +import * as ContextMenuActions from "../../pages/home/report/ContextMenu/ContextMenuActions"; +import * as ReportUtils from "../../libs/ReportUtils"; const propTypes = { /** Style for hovered state */ @@ -62,6 +69,7 @@ const OptionRowLHN = (props) => { } let touchableRef = null; + let popoverAnchor = null; const textStyle = props.isFocused ? styles.sidebarLinkActiveText : styles.sidebarLinkText; @@ -97,12 +105,38 @@ const OptionRowLHN = (props) => { const avatarTooltips = !optionItem.isChatRoom && !optionItem.isArchivedRoom ? _.pluck(optionItem.displayNamesWithTooltips, 'tooltip') : undefined; + /** + * Show the ReportActionContextMenu modal popover. + * + * @param {Object} [event] - A press event. + */ + const showPopover = (event) => { + ReportActionContextMenu.showContextMenu( + ContextMenuActions.CONTEXT_MENU_TYPES.REPORT, + event, + '', + popoverAnchor, + props.reportID, + {}, + '', + undefined, + undefined, + ); + }; + return ( + popoverAnchor = el} + onSecondaryInteraction={showPopover} + preventDefaultContentMenu + withoutFocusOnSecondaryInteraction + > {hovered => ( { )} + ); }; diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index 43e8f76f0df1..4c7907f75e3b 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -257,11 +257,11 @@ export default [ getDescription: () => {}, }, { - textTranslateKey: 'pin', + textTranslateKey: 'common.pin', icon: Expensicons.Pin, shouldShow: type => type === CONTEXT_MENU_TYPES.REPORT, - onPress: (closePopover, {report}) => { - Report.togglePinnedState(report); + onPress: (closePopover, {reportID}) => { + Report.togglePinnedState(reportID); if (closePopover) { hideContextMenu(true, ReportActionComposeFocusManager.focus); } diff --git a/src/pages/home/report/ContextMenu/ReportActionContextMenu.js b/src/pages/home/report/ContextMenu/ReportActionContextMenu.js index df544f2e7202..66b4303d976a 100644 --- a/src/pages/home/report/ContextMenu/ReportActionContextMenu.js +++ b/src/pages/home/report/ContextMenu/ReportActionContextMenu.js @@ -5,7 +5,7 @@ const contextMenuRef = React.createRef(); /** * Show the ReportActionContextMenu modal popover. * - * @param {string} type - the context menu type to display [EMAIL, LINK, REPORT_ACTION] + * @param {string} type - the context menu type to display [EMAIL, LINK, REPORT_ACTION, REPORT] * @param {Object} [event] - A press event. * @param {String} [selection] - Copied content. * @param {Element} contextMenuAnchor - popoverAnchor From d3befa3d4c42909a5c795b283c7d269fb78322ea Mon Sep 17 00:00:00 2001 From: Alberto Date: Fri, 17 Mar 2023 12:31:02 -0400 Subject: [PATCH 009/751] handle pin/unpin behavior --- src/components/LHNOptionsList/OptionRowLHN.js | 3 +++ src/languages/en.js | 2 ++ src/libs/actions/Report.js | 11 ++++++----- src/pages/home/HeaderView.js | 2 +- .../report/ContextMenu/BaseReportActionContextMenu.js | 1 + .../home/report/ContextMenu/ContextMenuActions.js | 6 ++++-- .../ContextMenu/PopoverReportActionContextMenu.js | 11 +++++++++-- .../report/ContextMenu/ReportActionContextMenu.js | 3 +++ 8 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/components/LHNOptionsList/OptionRowLHN.js b/src/components/LHNOptionsList/OptionRowLHN.js index 43c60b68f950..8258259ae46b 100644 --- a/src/components/LHNOptionsList/OptionRowLHN.js +++ b/src/components/LHNOptionsList/OptionRowLHN.js @@ -121,6 +121,9 @@ const OptionRowLHN = (props) => { '', undefined, undefined, + false, + false, + optionItem.isPinned, ); }; diff --git a/src/languages/en.js b/src/languages/en.js index 13e7af912018..d2777530fc27 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -47,6 +47,8 @@ export default { downloading: 'Downloading', pin: 'Pin', unPin: 'Unpin', + pinned: 'Pinned!', + unPinned: 'Unpinned!', back: 'Back', saveAndContinue: 'Save & continue', settings: 'Settings', diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 563816d396c1..a221d7075281 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -599,22 +599,23 @@ function markCommentAsUnread(reportID, reportActionCreated) { /** * Toggles the pinned state of the report. * - * @param {Object} report + * @param {Object} reportID + * @param {Boolean} isPinnedChat */ -function togglePinnedState(report) { - const pinnedValue = !report.isPinned; +function togglePinnedState(reportID, isPinnedChat) { + const pinnedValue = !isPinnedChat; // Optimistically pin/unpin the report before we send out the command const optimisticData = [ { onyxMethod: CONST.ONYX.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, value: {isPinned: pinnedValue}, }, ]; API.write('TogglePinnedChat', { - reportID: report.reportID, + reportID, pinnedValue, }, {optimisticData}); } diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index e1bfd267d8f2..4ec94739b3ea 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -158,7 +158,7 @@ const HeaderView = (props) => { {shouldShowCallButton && } Report.togglePinnedState(props.report)} + onPress={() => Report.togglePinnedState(props.report.reportID, props.report.isPinned)} style={[styles.touchableButtonImage]} > diff --git a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js index e562a417d423..ff8f6fa75a2c 100755 --- a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js +++ b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js @@ -72,6 +72,7 @@ class BaseReportActionContextMenu extends React.Component { const payload = { reportAction: this.props.reportAction, reportID: this.props.reportID, + isPinnedChat: this.props.isPinnedChat, draftMessage: this.props.draftMessage, selection: this.props.selection, close: () => this.setState({shouldKeepOpen: false}), diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index 4c7907f75e3b..70a6df9e5e2e 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -259,11 +259,13 @@ export default [ { textTranslateKey: 'common.pin', icon: Expensicons.Pin, + successTextTranslateKey: 'common.pinned', + successIcon: Expensicons.Checkmark, shouldShow: type => type === CONTEXT_MENU_TYPES.REPORT, onPress: (closePopover, {reportID}) => { - Report.togglePinnedState(reportID); + Report.togglePinnedState(reportID, false); if (closePopover) { - hideContextMenu(true, ReportActionComposeFocusManager.focus); + hideContextMenu(false); } }, getDescription: () => {}, diff --git a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.js b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.js index 0075df0cdd31..03f3c08103e1 100644 --- a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.js +++ b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.js @@ -38,6 +38,7 @@ class PopoverReportActionContextMenu extends React.Component { }, isArchivedRoom: false, isChronosReport: false, + isPinnedChat: false, }; this.onPopoverShow = () => {}; this.onPopoverHide = () => {}; @@ -124,6 +125,7 @@ class PopoverReportActionContextMenu extends React.Component { * @param {Function} [onHide] - Run a callback when Menu is hidden * @param {Boolean} isArchivedRoom - Whether the provided report is an archived room * @param {Boolean} isChronosReport - Flag to check if the chat participant is Chronos + * @param {Boolean} isPinnedChat - Flag to check if the chat is pinned in the LHN. Used for the Pin/Unpin action */ showContextMenu( type, @@ -135,8 +137,9 @@ class PopoverReportActionContextMenu extends React.Component { draftMessage, onShow = () => {}, onHide = () => {}, - isArchivedRoom, - isChronosReport, + isArchivedRoom = false, + isChronosReport = false, + isPinnedChat = false, ) { const nativeEvent = event.nativeEvent || {}; this.contextMenuAnchor = contextMenuAnchor; @@ -169,6 +172,7 @@ class PopoverReportActionContextMenu extends React.Component { reportActionDraftMessage: draftMessage, isArchivedRoom, isChronosReport, + isPinnedChat, }); }); } @@ -243,6 +247,7 @@ class PopoverReportActionContextMenu extends React.Component { reportAction={this.state.reportAction} isArchivedRoom={this.state.isArchivedRoom} isChronosReport={this.state.isChronosReport} + isPinnedChat={this.state.isPinnedChat} anchor={this.contextMenuTargetNode} contentRef={this.setContentRef} /> @@ -274,6 +279,7 @@ class PopoverReportActionContextMenu extends React.Component { shouldSetModalVisibilityForDeleteConfirmation: true, isArchivedRoom: false, isChronosReport: false, + isPinnedChat: false, }); } @@ -320,6 +326,7 @@ class PopoverReportActionContextMenu extends React.Component { draftMessage={this.state.reportActionDraftMessage} isArchivedRoom={this.state.isArchivedRoom} isChronosReport={this.state.isChronosReport} + isPinnedChat={this.state.isPinnedChat} anchor={this.contextMenuTargetNode} contentRef={this.contentRef} /> diff --git a/src/pages/home/report/ContextMenu/ReportActionContextMenu.js b/src/pages/home/report/ContextMenu/ReportActionContextMenu.js index 66b4303d976a..88ab4438242e 100644 --- a/src/pages/home/report/ContextMenu/ReportActionContextMenu.js +++ b/src/pages/home/report/ContextMenu/ReportActionContextMenu.js @@ -16,6 +16,7 @@ const contextMenuRef = React.createRef(); * @param {Function} [onHide=() => {}] - Run a callback when Menu is hidden * @param {Boolean} isArchivedRoom - Whether the provided report is an archived room * @param {Boolean} isChronosReport - Flag to check if the chat participant is Chronos + * @param {Boolean} isPinnedChat - Flag to check if the chat is pinned in the LHN. Used for the Pin/Unpin action */ function showContextMenu( type, @@ -29,6 +30,7 @@ function showContextMenu( onHide = () => {}, isArchivedRoom = false, isChronosReport = false, + isPinnedChat = false, ) { if (!contextMenuRef.current) { return; @@ -45,6 +47,7 @@ function showContextMenu( onHide, isArchivedRoom, isChronosReport, + isPinnedChat, ); } From 28079fed3a71f68536d5c6bd1918b41b68f86119 Mon Sep 17 00:00:00 2001 From: Alberto Date: Fri, 17 Mar 2023 12:31:27 -0400 Subject: [PATCH 010/751] no need fur success messages --- src/languages/en.js | 2 -- src/pages/home/report/ContextMenu/ContextMenuActions.js | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/languages/en.js b/src/languages/en.js index d2777530fc27..13e7af912018 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -47,8 +47,6 @@ export default { downloading: 'Downloading', pin: 'Pin', unPin: 'Unpin', - pinned: 'Pinned!', - unPinned: 'Unpinned!', back: 'Back', saveAndContinue: 'Save & continue', settings: 'Settings', diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index 70a6df9e5e2e..dc45f882b666 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -259,8 +259,6 @@ export default [ { textTranslateKey: 'common.pin', icon: Expensicons.Pin, - successTextTranslateKey: 'common.pinned', - successIcon: Expensicons.Checkmark, shouldShow: type => type === CONTEXT_MENU_TYPES.REPORT, onPress: (closePopover, {reportID}) => { Report.togglePinnedState(reportID, false); From c3c45ce6c87db5c87e08dcf0fa9a97ed7512fdae Mon Sep 17 00:00:00 2001 From: Alberto Date: Fri, 17 Mar 2023 13:30:30 -0400 Subject: [PATCH 011/751] figure out what's going on --- .../home/report/ContextMenu/ContextMenuActions.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index dc45f882b666..e8a75703c2ee 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -31,6 +31,10 @@ function getActionText(reportAction) { return lodashGet(message, 'html', ''); } +function pinText(isPinnedChat) { + return isPinnedChat ? 'common.unPin' : 'common.pin'; +} + const CONTEXT_MENU_TYPES = { LINK: 'LINK', REPORT_ACTION: 'REPORT_ACTION', @@ -257,11 +261,11 @@ export default [ getDescription: () => {}, }, { - textTranslateKey: 'common.pin', + textTranslateKey: (isPinnedChat) => pinText(isPinnedChat), icon: Expensicons.Pin, shouldShow: type => type === CONTEXT_MENU_TYPES.REPORT, - onPress: (closePopover, {reportID}) => { - Report.togglePinnedState(reportID, false); + onPress: (closePopover, {reportID, isPinnedChat}) => { + Report.togglePinnedState(reportID, isPinnedChat); if (closePopover) { hideContextMenu(false); } From a6e1aec28a6b3ceed52d083632ffebaf635d4602 Mon Sep 17 00:00:00 2001 From: Alberto Date: Fri, 17 Mar 2023 15:29:51 -0400 Subject: [PATCH 012/751] make pin/unpin work fine --- .../BaseReportActionContextMenu.js | 3 ++- .../report/ContextMenu/ContextMenuActions.js | 24 ++++++++++++------- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js index ff8f6fa75a2c..8988388b3fcd 100755 --- a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js +++ b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js @@ -60,6 +60,7 @@ class BaseReportActionContextMenu extends React.Component { this.props.betas, this.props.anchor, this.props.isChronosReport, + this.props.isPinnedChat, ); return (this.props.isVisible || this.state.shouldKeepOpen) && ( @@ -72,9 +73,9 @@ class BaseReportActionContextMenu extends React.Component { const payload = { reportAction: this.props.reportAction, reportID: this.props.reportID, - isPinnedChat: this.props.isPinnedChat, draftMessage: this.props.draftMessage, selection: this.props.selection, + isPinnedChat: this.props.isPinnedChat, close: () => this.setState({shouldKeepOpen: false}), openContextMenu: () => this.setState({shouldKeepOpen: true}), }; diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index e8a75703c2ee..93b302da770e 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -31,10 +31,6 @@ function getActionText(reportAction) { return lodashGet(message, 'html', ''); } -function pinText(isPinnedChat) { - return isPinnedChat ? 'common.unPin' : 'common.pin'; -} - const CONTEXT_MENU_TYPES = { LINK: 'LINK', REPORT_ACTION: 'REPORT_ACTION', @@ -261,11 +257,23 @@ export default [ getDescription: () => {}, }, { - textTranslateKey: (isPinnedChat) => pinText(isPinnedChat), + textTranslateKey: 'common.pin', + icon: Expensicons.Pin, + shouldShow: (type, reportAction, isArchivedRoom, betas, anchor, isChronosReport, isPinnedChat) => type === CONTEXT_MENU_TYPES.REPORT && !isPinnedChat, + onPress: (closePopover, {reportID}) => { + Report.togglePinnedState(reportID, false); + if (closePopover) { + hideContextMenu(false); + } + }, + getDescription: () => {}, + }, + { + textTranslateKey: 'common.unPin', icon: Expensicons.Pin, - shouldShow: type => type === CONTEXT_MENU_TYPES.REPORT, - onPress: (closePopover, {reportID, isPinnedChat}) => { - Report.togglePinnedState(reportID, isPinnedChat); + shouldShow: (type, reportAction, isArchivedRoom, betas, anchor, isChronosReport, isPinnedChat) => type === CONTEXT_MENU_TYPES.REPORT && isPinnedChat, + onPress: (closePopover, {reportID}) => { + Report.togglePinnedState(reportID, true); if (closePopover) { hideContextMenu(false); } From 6b26871161adc45e11ba8ae0791a1520598ff132 Mon Sep 17 00:00:00 2001 From: Alberto Date: Fri, 17 Mar 2023 15:31:56 -0400 Subject: [PATCH 013/751] cleanup --- src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js | 1 - src/pages/home/report/ContextMenu/ContextMenuActions.js | 1 - 2 files changed, 2 deletions(-) diff --git a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js index 8988388b3fcd..5e48e545b817 100755 --- a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js +++ b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js @@ -75,7 +75,6 @@ class BaseReportActionContextMenu extends React.Component { reportID: this.props.reportID, draftMessage: this.props.draftMessage, selection: this.props.selection, - isPinnedChat: this.props.isPinnedChat, close: () => this.setState({shouldKeepOpen: false}), openContextMenu: () => this.setState({shouldKeepOpen: true}), }; diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index 93b302da770e..c0193d84d262 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -19,7 +19,6 @@ import * as Environment from '../../../../libs/Environment/Environment'; import Permissions from '../../../../libs/Permissions'; import QuickEmojiReactions from '../../../../components/Reactions/QuickEmojiReactions'; import MiniQuickEmojiReactions from '../../../../components/Reactions/MiniQuickEmojiReactions'; -import {togglePinnedState} from "../../../../libs/actions/Report"; /** * Gets the HTML version of the message in an action. From cc83d47e94285216bac55465d27b0848bf7a9bdf Mon Sep 17 00:00:00 2001 From: Alberto Date: Fri, 17 Mar 2023 15:39:55 -0400 Subject: [PATCH 014/751] lint --- src/components/LHNOptionsList/OptionRowLHN.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/components/LHNOptionsList/OptionRowLHN.js b/src/components/LHNOptionsList/OptionRowLHN.js index 8258259ae46b..1f82ce5b9ad1 100644 --- a/src/components/LHNOptionsList/OptionRowLHN.js +++ b/src/components/LHNOptionsList/OptionRowLHN.js @@ -24,13 +24,9 @@ import themeColors from '../../styles/themes/default'; import SidebarUtils from '../../libs/SidebarUtils'; import TextPill from '../TextPill'; import OfflineWithFeedback from '../OfflineWithFeedback'; -import * as DeviceCapabilities from "../../libs/DeviceCapabilities"; -import ControlSelection from "../../libs/ControlSelection"; -import PressableWithSecondaryInteraction from "../PressableWithSecondaryInteraction"; -import SelectionScraper from "../../libs/SelectionScraper"; -import * as ReportActionContextMenu from "../../pages/home/report/ContextMenu/ReportActionContextMenu"; -import * as ContextMenuActions from "../../pages/home/report/ContextMenu/ContextMenuActions"; -import * as ReportUtils from "../../libs/ReportUtils"; +import PressableWithSecondaryInteraction from '../PressableWithSecondaryInteraction'; +import * as ReportActionContextMenu from '../../pages/home/report/ContextMenu/ReportActionContextMenu'; +import * as ContextMenuActions from '../../pages/home/report/ContextMenu/ContextMenuActions'; const propTypes = { /** Style for hovered state */ From 6d65fb8874a00a8a38c4aba1e07572b71988590f Mon Sep 17 00:00:00 2001 From: Alberto Date: Fri, 17 Mar 2023 15:59:08 -0400 Subject: [PATCH 015/751] more lint cleanup --- src/components/LHNOptionsList/OptionRowLHN.js | 250 +++++++++--------- 1 file changed, 125 insertions(+), 125 deletions(-) diff --git a/src/components/LHNOptionsList/OptionRowLHN.js b/src/components/LHNOptionsList/OptionRowLHN.js index 1f82ce5b9ad1..eae12e9519f3 100644 --- a/src/components/LHNOptionsList/OptionRowLHN.js +++ b/src/components/LHNOptionsList/OptionRowLHN.js @@ -130,146 +130,146 @@ const OptionRowLHN = (props) => { shouldShowErrorMessages={false} > popoverAnchor = el} onSecondaryInteraction={showPopover} preventDefaultContentMenu withoutFocusOnSecondaryInteraction > - - {hovered => ( - touchableRef = el} - onPress={(e) => { - if (e) { - e.preventDefault(); - } + + {hovered => ( + touchableRef = el} + onPress={(e) => { + if (e) { + e.preventDefault(); + } - props.onSelectRow(optionItem, touchableRef); - }} - activeOpacity={0.8} - style={[ - styles.flexRow, - styles.alignItemsCenter, - styles.justifyContentBetween, - styles.sidebarLink, - styles.sidebarLinkInner, - StyleUtils.getBackgroundColorStyle(themeColors.sidebar), - props.isFocused ? styles.sidebarLinkActive : null, - hovered && !props.isFocused ? props.hoverStyle : null, - ]} - > - - - { - !_.isEmpty(optionItem.icons) - && ( - optionItem.shouldShowSubscript ? ( - - ) : ( - + props.onSelectRow(optionItem, touchableRef); + }} + activeOpacity={0.8} + style={[ + styles.flexRow, + styles.alignItemsCenter, + styles.justifyContentBetween, + styles.sidebarLink, + styles.sidebarLinkInner, + StyleUtils.getBackgroundColorStyle(themeColors.sidebar), + props.isFocused ? styles.sidebarLinkActive : null, + hovered && !props.isFocused ? props.hoverStyle : null, + ]} + > + + + { + !_.isEmpty(optionItem.icons) + && ( + optionItem.shouldShowSubscript ? ( + + ) : ( + + ) ) - ) - } - - - - {optionItem.isChatRoom && ( - + + - )} + {optionItem.isChatRoom && ( + + )} + + {optionItem.alternateText ? ( + + {optionItem.alternateText} + + ) : null} - {optionItem.alternateText ? ( - - {optionItem.alternateText} - + {optionItem.descriptiveText ? ( + + + {optionItem.descriptiveText} + + ) : null} + {optionItem.brickRoadIndicator === CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR && ( + + + + )} - {optionItem.descriptiveText ? ( - - - {optionItem.descriptiveText} - + + + {optionItem.hasDraftComment && ( + + - ) : null} - {optionItem.brickRoadIndicator === CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR && ( - - + )} + {optionItem.hasOutstandingIOU && } + {optionItem.isPinned && ( + + )} - - - {optionItem.hasDraftComment && ( - - - - )} - {optionItem.hasOutstandingIOU && } - {optionItem.isPinned && ( - - - - )} - - - )} - + + )} + ); From 96c8256cb8bc443365af9d1528907c8071f91708 Mon Sep 17 00:00:00 2001 From: Alberto Date: Fri, 17 Mar 2023 16:00:45 -0400 Subject: [PATCH 016/751] update test --- tests/actions/ReportTest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/actions/ReportTest.js b/tests/actions/ReportTest.js index 34c7c665b7d6..57a164dd2625 100644 --- a/tests/actions/ReportTest.js +++ b/tests/actions/ReportTest.js @@ -162,7 +162,7 @@ describe('actions/Report', () => { // Set up Onyx with some test user data return TestHelper.signInWithTestUser(TEST_USER_ACCOUNT_ID, TEST_USER_LOGIN) .then(() => { - Report.togglePinnedState(REPORT); + Report.togglePinnedState(REPORT_ID, false); return waitForPromisesToResolve(); }) .then(() => { From eafa87fbe4194d602d361c87875c82b2a72a2038 Mon Sep 17 00:00:00 2001 From: Alberto Date: Sat, 18 Mar 2023 15:05:05 -0400 Subject: [PATCH 017/751] handle mobile devices --- src/components/LHNOptionsList/OptionRowLHN.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/LHNOptionsList/OptionRowLHN.js b/src/components/LHNOptionsList/OptionRowLHN.js index eae12e9519f3..5e416c72ebed 100644 --- a/src/components/LHNOptionsList/OptionRowLHN.js +++ b/src/components/LHNOptionsList/OptionRowLHN.js @@ -27,6 +27,8 @@ import OfflineWithFeedback from '../OfflineWithFeedback'; import PressableWithSecondaryInteraction from '../PressableWithSecondaryInteraction'; import * as ReportActionContextMenu from '../../pages/home/report/ContextMenu/ReportActionContextMenu'; import * as ContextMenuActions from '../../pages/home/report/ContextMenu/ContextMenuActions'; +import ControlSelection from '../../libs/ControlSelection'; +import * as DeviceCapabilities from '../../libs/DeviceCapabilities'; const propTypes = { /** Style for hovered state */ @@ -132,6 +134,8 @@ const OptionRowLHN = (props) => { popoverAnchor = el} + onPressIn={() => props.isSmallScreenWidth && DeviceCapabilities.canUseTouchScreen() && ControlSelection.block()} + onPressOut={() => ControlSelection.unblock()} onSecondaryInteraction={showPopover} preventDefaultContentMenu withoutFocusOnSecondaryInteraction From 315fbc66b894d40e809750d0f7f3bcc2c1db7ebf Mon Sep 17 00:00:00 2001 From: Alberto Date: Wed, 22 Mar 2023 16:26:59 +0100 Subject: [PATCH 018/751] Use pressablewithSecondaryInteraction instead of touchableOpacity --- src/components/LHNOptionsList/OptionRowLHN.js | 25 +++++++------------ 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/src/components/LHNOptionsList/OptionRowLHN.js b/src/components/LHNOptionsList/OptionRowLHN.js index 49c196b13a90..ee3ca10ef552 100644 --- a/src/components/LHNOptionsList/OptionRowLHN.js +++ b/src/components/LHNOptionsList/OptionRowLHN.js @@ -67,7 +67,6 @@ const OptionRowLHN = (props) => { return null; } - let touchableRef = null; let popoverAnchor = null; const textStyle = props.isFocused ? styles.sidebarLinkActiveText @@ -110,6 +109,7 @@ const OptionRowLHN = (props) => { * @param {Object} [event] - A press event. */ const showPopover = (event) => { + console.log('here'); ReportActionContextMenu.showContextMenu( ContextMenuActions.CONTEXT_MENU_TYPES.REPORT, event, @@ -132,27 +132,21 @@ const OptionRowLHN = (props) => { errors={optionItem.allReportErrors} shouldShowErrorMessages={false} > - popoverAnchor = el} - onPressIn={() => props.isSmallScreenWidth && DeviceCapabilities.canUseTouchScreen() && ControlSelection.block()} - onPressOut={() => ControlSelection.unblock()} - onSecondaryInteraction={showPopover} - preventDefaultContentMenu - withoutFocusOnSecondaryInteraction - > {hovered => ( - touchableRef = el} + popoverAnchor = el} onPress={(e) => { if (e) { e.preventDefault(); } - props.onSelectRow(optionItem, touchableRef); + props.onSelectRow(optionItem, popoverAnchor); }} - activeOpacity={0.8} + onSecondaryInteraction={e => showPopover(e)} + preventDefaultContentMenu + withoutFocusOnSecondaryInteraction style={[ styles.flexRow, styles.alignItemsCenter, @@ -272,10 +266,9 @@ const OptionRowLHN = (props) => { )} - + )} - ); }; From 7ef10b8e85f54ea7a4dc234053910e882d929801 Mon Sep 17 00:00:00 2001 From: Alberto Date: Wed, 22 Mar 2023 16:31:13 +0100 Subject: [PATCH 019/751] Turn Pressable into touchableOpacity --- src/components/LHNOptionsList/OptionRowLHN.js | 1 + src/components/PressableWithSecondaryInteraction/index.js | 7 ++++--- .../PressableWithSecondaryInteraction/index.native.js | 5 +++-- .../pressableWithSecondaryInteractionPropTypes.js | 3 +++ 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/components/LHNOptionsList/OptionRowLHN.js b/src/components/LHNOptionsList/OptionRowLHN.js index ee3ca10ef552..008ad285e43b 100644 --- a/src/components/LHNOptionsList/OptionRowLHN.js +++ b/src/components/LHNOptionsList/OptionRowLHN.js @@ -147,6 +147,7 @@ const OptionRowLHN = (props) => { onSecondaryInteraction={e => showPopover(e)} preventDefaultContentMenu withoutFocusOnSecondaryInteraction + activeOpacity={0.8} style={[ styles.flexRow, styles.alignItemsCenter, diff --git a/src/components/PressableWithSecondaryInteraction/index.js b/src/components/PressableWithSecondaryInteraction/index.js index f3ea25a471fd..bc1d7895f6e6 100644 --- a/src/components/PressableWithSecondaryInteraction/index.js +++ b/src/components/PressableWithSecondaryInteraction/index.js @@ -1,6 +1,6 @@ import _ from 'underscore'; import React, {Component} from 'react'; -import {Pressable} from 'react-native'; +import {Pressable, TouchableOpacity} from 'react-native'; import * as pressableWithSecondaryInteractionPropTypes from './pressableWithSecondaryInteractionPropTypes'; import styles from '../../styles/styles'; import * as DeviceCapabilities from '../../libs/DeviceCapabilities'; @@ -53,7 +53,7 @@ class PressableWithSecondaryInteraction extends Component { // On Web, Text does not support LongPress events thus manage inline mode with styling instead of using Text. return ( - { @@ -65,6 +65,7 @@ class PressableWithSecondaryInteraction extends Component { } this.props.onSecondaryInteraction(e); }} + activeOpacity={this.props.activeOpacity} onPressOut={this.props.onPressOut} onPress={this.props.onPress} ref={el => this.pressableRef = el} @@ -72,7 +73,7 @@ class PressableWithSecondaryInteraction extends Component { {...defaultPressableProps} > {this.props.children} - + ); } } diff --git a/src/components/PressableWithSecondaryInteraction/index.native.js b/src/components/PressableWithSecondaryInteraction/index.native.js index f186146b4134..111c210efeed 100644 --- a/src/components/PressableWithSecondaryInteraction/index.native.js +++ b/src/components/PressableWithSecondaryInteraction/index.native.js @@ -1,6 +1,6 @@ import _ from 'underscore'; import React, {forwardRef} from 'react'; -import {Pressable} from 'react-native'; +import {Pressable, TouchableOpacity} from 'react-native'; import * as pressableWithSecondaryInteractionPropTypes from './pressableWithSecondaryInteractionPropTypes'; import Text from '../Text'; import HapticFeedback from '../../libs/HapticFeedback'; @@ -13,7 +13,7 @@ import HapticFeedback from '../../libs/HapticFeedback'; */ const PressableWithSecondaryInteraction = (props) => { // Use Text node for inline mode to prevent content overflow. - const Node = props.inline ? Text : Pressable; + const Node = props.inline ? Text : TouchableOpacity; return ( { }} onPressIn={props.onPressIn} onPressOut={props.onPressOut} + activeOpacity={props.activeOpacity} // eslint-disable-next-line react/jsx-props-no-spreading {...(_.omit(props, 'onLongPress'))} > diff --git a/src/components/PressableWithSecondaryInteraction/pressableWithSecondaryInteractionPropTypes.js b/src/components/PressableWithSecondaryInteraction/pressableWithSecondaryInteractionPropTypes.js index bffe11bc4cd8..2201e93d9e98 100644 --- a/src/components/PressableWithSecondaryInteraction/pressableWithSecondaryInteractionPropTypes.js +++ b/src/components/PressableWithSecondaryInteraction/pressableWithSecondaryInteractionPropTypes.js @@ -34,6 +34,8 @@ const propTypes = { /** Disable focus trap for the element on secondary interaction */ withoutFocusOnSecondaryInteraction: PropTypes.bool, + + activeOpacity: PropTypes.number, }; const defaultProps = { @@ -43,6 +45,7 @@ const defaultProps = { preventDefaultContentMenu: true, inline: false, withoutFocusOnSecondaryInteraction: false, + activeOpacity: 1, }; export {propTypes, defaultProps}; From 5803c474bc0d69c8d58f4479cb6efdd8821791b2 Mon Sep 17 00:00:00 2001 From: Alberto Date: Wed, 22 Mar 2023 16:33:16 +0100 Subject: [PATCH 020/751] cleanUp --- src/components/LHNOptionsList/OptionRowLHN.js | 260 +++++++++--------- .../index.js | 2 +- .../index.native.js | 2 +- ...ssableWithSecondaryInteractionPropTypes.js | 2 + 4 files changed, 132 insertions(+), 134 deletions(-) diff --git a/src/components/LHNOptionsList/OptionRowLHN.js b/src/components/LHNOptionsList/OptionRowLHN.js index 008ad285e43b..18388c907d31 100644 --- a/src/components/LHNOptionsList/OptionRowLHN.js +++ b/src/components/LHNOptionsList/OptionRowLHN.js @@ -2,7 +2,6 @@ import _ from 'underscore'; import React from 'react'; import PropTypes from 'prop-types'; import { - TouchableOpacity, View, StyleSheet, } from 'react-native'; @@ -28,8 +27,6 @@ import OfflineWithFeedback from '../OfflineWithFeedback'; import PressableWithSecondaryInteraction from '../PressableWithSecondaryInteraction'; import * as ReportActionContextMenu from '../../pages/home/report/ContextMenu/ReportActionContextMenu'; import * as ContextMenuActions from '../../pages/home/report/ContextMenu/ContextMenuActions'; -import ControlSelection from '../../libs/ControlSelection'; -import * as DeviceCapabilities from '../../libs/DeviceCapabilities'; const propTypes = { /** Style for hovered state */ @@ -109,7 +106,6 @@ const OptionRowLHN = (props) => { * @param {Object} [event] - A press event. */ const showPopover = (event) => { - console.log('here'); ReportActionContextMenu.showContextMenu( ContextMenuActions.CONTEXT_MENU_TYPES.REPORT, event, @@ -132,144 +128,144 @@ const OptionRowLHN = (props) => { errors={optionItem.allReportErrors} shouldShowErrorMessages={false} > - - {hovered => ( - popoverAnchor = el} - onPress={(e) => { - if (e) { - e.preventDefault(); - } + + {hovered => ( + popoverAnchor = el} + onPress={(e) => { + if (e) { + e.preventDefault(); + } - props.onSelectRow(optionItem, popoverAnchor); - }} - onSecondaryInteraction={e => showPopover(e)} - preventDefaultContentMenu - withoutFocusOnSecondaryInteraction - activeOpacity={0.8} - style={[ - styles.flexRow, - styles.alignItemsCenter, - styles.justifyContentBetween, - styles.sidebarLink, - styles.sidebarLinkInner, - StyleUtils.getBackgroundColorStyle(themeColors.sidebar), - props.isFocused ? styles.sidebarLinkActive : null, - hovered && !props.isFocused ? props.hoverStyle : null, - ]} - > - - - { - !_.isEmpty(optionItem.icons) - && ( - optionItem.shouldShowSubscript ? ( - - ) : ( - - ) + props.onSelectRow(optionItem, popoverAnchor); + }} + onSecondaryInteraction={e => showPopover(e)} + preventDefaultContentMenu + withoutFocusOnSecondaryInteraction + activeOpacity={0.8} + style={[ + styles.flexRow, + styles.alignItemsCenter, + styles.justifyContentBetween, + styles.sidebarLink, + styles.sidebarLinkInner, + StyleUtils.getBackgroundColorStyle(themeColors.sidebar), + props.isFocused ? styles.sidebarLinkActive : null, + hovered && !props.isFocused ? props.hoverStyle : null, + ]} + > + + + { + !_.isEmpty(optionItem.icons) + && ( + optionItem.shouldShowSubscript ? ( + + ) : ( + ) - } - - - + + + {optionItem.isChatRoom && ( + - {optionItem.isChatRoom && ( - - )} - - {optionItem.alternateText ? ( - - {optionItem.alternateText} - - ) : null} + )} - {optionItem.descriptiveText ? ( - - - {optionItem.descriptiveText} - - + {optionItem.alternateText ? ( + + {optionItem.alternateText} + ) : null} - {optionItem.brickRoadIndicator === CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR && ( - - - - )} - - - {optionItem.hasDraftComment && ( - - + {optionItem.descriptiveText ? ( + + + {optionItem.descriptiveText} + - )} - {optionItem.hasOutstandingIOU && } - {optionItem.isPinned && ( - - + ) : null} + {optionItem.brickRoadIndicator === CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR && ( + + )} - - )} - + + + {optionItem.hasDraftComment && ( + + + + )} + {optionItem.hasOutstandingIOU && } + {optionItem.isPinned && ( + + + + )} + + + )} + ); }; diff --git a/src/components/PressableWithSecondaryInteraction/index.js b/src/components/PressableWithSecondaryInteraction/index.js index bc1d7895f6e6..1615b4344961 100644 --- a/src/components/PressableWithSecondaryInteraction/index.js +++ b/src/components/PressableWithSecondaryInteraction/index.js @@ -1,6 +1,6 @@ import _ from 'underscore'; import React, {Component} from 'react'; -import {Pressable, TouchableOpacity} from 'react-native'; +import {TouchableOpacity} from 'react-native'; import * as pressableWithSecondaryInteractionPropTypes from './pressableWithSecondaryInteractionPropTypes'; import styles from '../../styles/styles'; import * as DeviceCapabilities from '../../libs/DeviceCapabilities'; diff --git a/src/components/PressableWithSecondaryInteraction/index.native.js b/src/components/PressableWithSecondaryInteraction/index.native.js index 111c210efeed..1fc437e9f737 100644 --- a/src/components/PressableWithSecondaryInteraction/index.native.js +++ b/src/components/PressableWithSecondaryInteraction/index.native.js @@ -1,6 +1,6 @@ import _ from 'underscore'; import React, {forwardRef} from 'react'; -import {Pressable, TouchableOpacity} from 'react-native'; +import {TouchableOpacity} from 'react-native'; import * as pressableWithSecondaryInteractionPropTypes from './pressableWithSecondaryInteractionPropTypes'; import Text from '../Text'; import HapticFeedback from '../../libs/HapticFeedback'; diff --git a/src/components/PressableWithSecondaryInteraction/pressableWithSecondaryInteractionPropTypes.js b/src/components/PressableWithSecondaryInteraction/pressableWithSecondaryInteractionPropTypes.js index 2201e93d9e98..2d2e533f97f9 100644 --- a/src/components/PressableWithSecondaryInteraction/pressableWithSecondaryInteractionPropTypes.js +++ b/src/components/PressableWithSecondaryInteraction/pressableWithSecondaryInteractionPropTypes.js @@ -27,6 +27,7 @@ const propTypes = { * * - No support for delayLongPress. * - No support for pressIn and pressOut events. + * - No support for opacity * * Note: Web uses styling instead of Text due to no support of LongPress. Thus above pointers are not valid for web. */ @@ -35,6 +36,7 @@ const propTypes = { /** Disable focus trap for the element on secondary interaction */ withoutFocusOnSecondaryInteraction: PropTypes.bool, + /** Opacity to reduce to when active */ activeOpacity: PropTypes.number, }; From 9f4349db276074642fee8c58e15c51d52204bb21 Mon Sep 17 00:00:00 2001 From: Alberto Date: Wed, 22 Mar 2023 16:43:53 +0100 Subject: [PATCH 021/751] update test --- tests/actions/ReportTest.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/actions/ReportTest.js b/tests/actions/ReportTest.js index 57a164dd2625..97f767bc86b7 100644 --- a/tests/actions/ReportTest.js +++ b/tests/actions/ReportTest.js @@ -148,10 +148,6 @@ describe('actions/Report', () => { const TEST_USER_ACCOUNT_ID = 1; const TEST_USER_LOGIN = 'test@test.com'; const REPORT_ID = '1'; - const REPORT = { - reportID: REPORT_ID, - isPinned: false, - }; let reportIsPinned; Onyx.connect({ From 9b3b430e1a9515f9ccb955d0aafc1dda177312cd Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Mon, 3 Apr 2023 08:40:49 -1000 Subject: [PATCH 022/751] Add some frequently asked questions --- contributingGuides/STYLE.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/contributingGuides/STYLE.md b/contributingGuides/STYLE.md index 9d94623f0e33..1dd5ee7d92df 100644 --- a/contributingGuides/STYLE.md +++ b/contributingGuides/STYLE.md @@ -618,6 +618,24 @@ There are several ways to use and declare refs and we prefer the [callback metho We love React and learning about all the new features that are regularly being added to the API. However, we try to keep our organization's usage of React limited to the most stable set of features that React offers. We do this mainly for **consistency** and so our engineers don't have to spend extra time trying to figure out how everything is working. That said, if you aren't sure if we have adopted something please ask us first. +# React Hooks: Frequently Asked Questions + +## Are Hooks a Replacement for HOCs or Render Props? + +In most cases, a custom hook is a better pattern to use than an HOC or Render Prop. They are easier to create, understand, use and document. However, there might still be a case for a HOC e.g. if you have a component that abstracts some conditional rendering logic. + +## Where should I put my inline functions? I'm getting a lint error related to `jsx-no-bind`... + +If your inline function does not have any dependencies (i.e. props or state that it depends on) it can be removed from the component and moved to the top of the file. If it does have dependencies, then we should wrap it in `useCallback()` and pass the dependencies as an argument. At one time, we questioned whether there is some performance penalty to using `useCallback()` as a pre-optimization and the conclusion was that there is generally a higher potential cost to not using it vs. using it. + +## Is there an equivalent to `componentDidUpdate()` when using hooks? + +The short answer is no. A longer answer is that sometimes we need to check not only that a dependency has changed, but how it has changed in order to run a side effect. For example, a prop had a value of an empty string on a previous render, but now is non-empty. The generally accepted practice is to store the "previous" value in a `ref` so the comparison can be made in a `useEffect()` call. + +## What is the `exhaustive-deps` lint rule? Can I ignore it? + +A `useEffect()` that does not include referenced props or state in its dependency array is [usually a mistake](https://legacy.reactjs.org/docs/hooks-faq.html#is-it-safe-to-omit-functions-from-the-list-of-dependencies) as often we want effects to re-run when those dependencies change. However, there are some cases where we might actually only want to re-run the effect when only some of those dependencies change. We determined the best practice here should be to allow disabling the “next line” with a comment `//eslint-disable-next-line react-hooks/exhaustive-deps` and an additional comment explanation so the next developer can understand why the rule was not used. + # Onyx Best Practices [Onyx Documentation](https://github.com/expensify/react-native-onyx) From 223a550d40c4f613a7382c5f8d3c25ddfb7b0c0b Mon Sep 17 00:00:00 2001 From: Alberto Date: Tue, 4 Apr 2023 16:45:17 +0200 Subject: [PATCH 023/751] add better defaults --- src/components/LHNOptionsList/OptionRowLHN.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/LHNOptionsList/OptionRowLHN.js b/src/components/LHNOptionsList/OptionRowLHN.js index d4d80328829a..5f7e34e412e5 100644 --- a/src/components/LHNOptionsList/OptionRowLHN.js +++ b/src/components/LHNOptionsList/OptionRowLHN.js @@ -113,8 +113,8 @@ const OptionRowLHN = (props) => { props.reportID, {}, '', - undefined, - undefined, + () => {}, + () => {}, false, false, optionItem.isPinned, From 95de7c2298b5bf36e7e222cd1c706da06314f63e Mon Sep 17 00:00:00 2001 From: Alberto Date: Wed, 5 Apr 2023 14:08:41 +0200 Subject: [PATCH 024/751] remove unneeded props --- src/components/LHNOptionsList/OptionRowLHN.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/LHNOptionsList/OptionRowLHN.js b/src/components/LHNOptionsList/OptionRowLHN.js index 5f7e34e412e5..0ba518b55c6e 100644 --- a/src/components/LHNOptionsList/OptionRowLHN.js +++ b/src/components/LHNOptionsList/OptionRowLHN.js @@ -130,7 +130,6 @@ const OptionRowLHN = (props) => { {hovered => ( popoverAnchor = el} onPress={(e) => { if (e) { @@ -140,7 +139,6 @@ const OptionRowLHN = (props) => { props.onSelectRow(optionItem, popoverAnchor); }} onSecondaryInteraction={e => showPopover(e)} - preventDefaultContentMenu withoutFocusOnSecondaryInteraction activeOpacity={0.8} style={[ From 5f96597c76211344472c73b7b365280feef11bd1 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Wed, 5 Apr 2023 13:37:29 -1000 Subject: [PATCH 025/751] Add some notes about useState()` --- contributingGuides/STYLE.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contributingGuides/STYLE.md b/contributingGuides/STYLE.md index 1dd5ee7d92df..fb7c71cb02f1 100644 --- a/contributingGuides/STYLE.md +++ b/contributingGuides/STYLE.md @@ -628,6 +628,10 @@ In most cases, a custom hook is a better pattern to use than an HOC or Render Pr If your inline function does not have any dependencies (i.e. props or state that it depends on) it can be removed from the component and moved to the top of the file. If it does have dependencies, then we should wrap it in `useCallback()` and pass the dependencies as an argument. At one time, we questioned whether there is some performance penalty to using `useCallback()` as a pre-optimization and the conclusion was that there is generally a higher potential cost to not using it vs. using it. +## Why does `useState()` sometimes get initialized with a function? + +React saves the initial state once and ignores it on the next renders. However, if you pass the result of a function to `useState()` or call a function directly e.g. `useState(doExpensiveThings())` it will *still run on every render*. This can hurt performance depending on what work the function is doing. As an optimization, we can pass an initializer function instead of a value e.g. `useState(doExpensiveThings)` or `useState(() => doExpensiveThings())`. + ## Is there an equivalent to `componentDidUpdate()` when using hooks? The short answer is no. A longer answer is that sometimes we need to check not only that a dependency has changed, but how it has changed in order to run a side effect. For example, a prop had a value of an empty string on a previous render, but now is non-empty. The generally accepted practice is to store the "previous" value in a `ref` so the comparison can be made in a `useEffect()` call. From a0090b625e380690b87e417126245e6e35b21693 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Fri, 14 Apr 2023 14:15:57 +0800 Subject: [PATCH 026/751] remove focusable and onblur --- src/components/Tooltip/index.js | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/src/components/Tooltip/index.js b/src/components/Tooltip/index.js index b3c555db5da0..87719910f21c 100644 --- a/src/components/Tooltip/index.js +++ b/src/components/Tooltip/index.js @@ -37,7 +37,6 @@ class Tooltip extends PureComponent { this.getWrapperPosition = this.getWrapperPosition.bind(this); this.showTooltip = this.showTooltip.bind(this); this.hideTooltip = this.hideTooltip.bind(this); - this.isFocusable = this.isFocusable.bind(this); } componentDidUpdate(prevProps) { @@ -142,17 +141,6 @@ class Tooltip extends PureComponent { TooltipSense.deactivate(); } - /** - * Returns true if children is a focusable component. - * - * @returns {Boolean} - */ - isFocusable() { - const name = this.props.children.type.displayName; - const isPressableText = name === 'Text' && Boolean(this.props.children.props.onPress); - return isPressableText || ['TouchableOpacity', 'Pressable', 'TouchableWithoutFeedback'].includes(name); - } - render() { // Skip the tooltip and return the children if the text is empty, // we don't have a render function or the device does not support hovering @@ -174,16 +162,6 @@ class Tooltip extends PureComponent { ref(el); } }, - onBlur: (el) => { - this.hideTooltip(); - - // Call the original onBlur, if any - const {onBlur} = this.props.children; - if (_.isFunction(onBlur)) { - onBlur(el); - } - }, - focusable: this.isFocusable(), }); return ( From c8cf0d26e69a40d56e61e7d5badc385ab48d5d57 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Fri, 14 Apr 2023 14:18:05 +0800 Subject: [PATCH 027/751] revert wrong change --- src/components/Reactions/AddReactionBubble.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Reactions/AddReactionBubble.js b/src/components/Reactions/AddReactionBubble.js index cc19b41dc2a7..0053da3ba6e7 100644 --- a/src/components/Reactions/AddReactionBubble.js +++ b/src/components/Reactions/AddReactionBubble.js @@ -66,7 +66,7 @@ const AddReactionBubble = (props) => { }; return ( - + Date: Fri, 14 Apr 2023 17:27:38 +0800 Subject: [PATCH 028/751] refactor tooltip usage --- src/components/AttachmentCarousel/index.js | 16 +++++----- src/components/AttachmentView.js | 8 ++--- .../AvatarCropModal/AvatarCropModal.js | 18 ++++++----- src/components/AvatarWithImagePicker.js | 32 ++++++++++--------- src/components/CopyTextToClipboard.js | 17 ++++++---- .../EmojiPicker/EmojiPickerButton.js | 2 +- .../BaseQuickEmojiReactions.js | 16 ++++++---- src/pages/home/HeaderView.js | 4 ++- src/pages/workspace/WorkspaceInitialPage.js | 1 - 9 files changed, 62 insertions(+), 52 deletions(-) diff --git a/src/components/AttachmentCarousel/index.js b/src/components/AttachmentCarousel/index.js index c2caebcc07a2..1993032cdc79 100644 --- a/src/components/AttachmentCarousel/index.js +++ b/src/components/AttachmentCarousel/index.js @@ -168,8 +168,8 @@ class AttachmentCarousel extends React.Component { {(isPageSet && this.state.shouldShowArrow) && ( <> {!this.state.isBackDisabled && ( - - + + + } + ) : ( )} - {moderationDecision === 'approved' && + {!props.displayAsGroup && moderationDecision !== 'approved' && } ); @@ -368,6 +380,7 @@ function ReportActionItem(props) { wrapperStyles={[styles.chatItem, isWhisper ? styles.pt1 : {}]} shouldShowSubscriptAvatar={props.shouldShowSubscriptAvatar} report={props.report} + isHidden={isHidden} > {content} diff --git a/src/pages/home/report/ReportActionItemMessage.js b/src/pages/home/report/ReportActionItemMessage.js index c6ad45968bbd..057795079a63 100644 --- a/src/pages/home/report/ReportActionItemMessage.js +++ b/src/pages/home/report/ReportActionItemMessage.js @@ -1,5 +1,5 @@ import React from 'react'; -import {View} from 'react-native'; +import {View, Text} from 'react-native'; import PropTypes from 'prop-types'; import _ from 'underscore'; import lodashGet from 'lodash/get'; @@ -39,7 +39,7 @@ const ReportActionItemMessage = (props) => ( loading={props.action.isLoading} style={props.style} /> - )) : 'hi'} + )) : This message has been flagged as violating our community rules and the content has been hidden.} ); diff --git a/src/pages/home/report/ReportActionItemSingle.js b/src/pages/home/report/ReportActionItemSingle.js index f388faf1b5a4..ceb248dfb0ea 100644 --- a/src/pages/home/report/ReportActionItemSingle.js +++ b/src/pages/home/report/ReportActionItemSingle.js @@ -127,7 +127,9 @@ const ReportActionItemSingle = (props) => { ) : null} - {props.children} + + {props.children} + ); diff --git a/src/styles/styles.js b/src/styles/styles.js index 5d7f0952a627..7ef46639a694 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -1018,6 +1018,10 @@ const styles = { lineHeight: 16, }, + lh20: { + lineHeight: 20, + }, + lh140Percent: { lineHeight: '140%', }, From f831821c19322b6b5d43d0d1f3656a0e9f47cc29 Mon Sep 17 00:00:00 2001 From: Daniel Gale-Rosen Date: Tue, 23 May 2023 14:51:23 -0400 Subject: [PATCH 198/751] cleanup --- src/pages/home/report/ReportActionItem.js | 7 ++++--- src/pages/home/report/ReportActionItemSingle.js | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index c23fc3b79ed4..957f135e9533 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -267,6 +267,7 @@ function ReportActionItem(props) { ); } else { const message = _.last(lodashGet(props.action, 'message', [{}])); + const hasBeenFlagged = moderationDecision !== 'approved'; const isAttachment = _.has(props.action, 'isAttachment') ? props.action.isAttachment : ReportUtils.isReportMessageAttachment(message); children = ( {!props.draftMessage ? ( - + - {props.displayAsGroup && moderationDecision !== 'approved' && + {props.displayAsGroup && hasBeenFlagged && } diff --git a/src/pages/home/report/ReportActionItemMessage.js b/src/pages/home/report/ReportActionItemMessage.js index 057795079a63..8b93cd1668d3 100644 --- a/src/pages/home/report/ReportActionItemMessage.js +++ b/src/pages/home/report/ReportActionItemMessage.js @@ -39,7 +39,7 @@ const ReportActionItemMessage = (props) => ( loading={props.action.isLoading} style={props.style} /> - )) : This message has been flagged as violating our community rules and the content has been hidden.} + )) : {props.translate('moderation.flaggedContent')}} ); From 78304b713106099f1a931d4dabbf100232334045 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Thu, 25 May 2023 15:36:46 -0600 Subject: [PATCH 316/751] return correct errors --- src/components/Form.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Form.js b/src/components/Form.js index f895075fcd03..8f1b70fb1c6b 100644 --- a/src/components/Form.js +++ b/src/components/Form.js @@ -139,7 +139,7 @@ const Form = (props) => { setErrors(touchedInputErrors); } - return errors; + return touchedInputErrors; }, [errors, touchedInputs, props.formID, validate, translate], ); From a3d0464f0af3c90d1292f46005e05a37dbdd106a Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Thu, 25 May 2023 16:07:33 -0600 Subject: [PATCH 317/751] fix destructuring for functional children --- src/components/Form.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Form.js b/src/components/Form.js index 8f1b70fb1c6b..7ec91d508b8e 100644 --- a/src/components/Form.js +++ b/src/components/Form.js @@ -317,7 +317,7 @@ const Form = (props) => { style={StyleSheet.flatten([props.style, safeAreaPaddingBottomStyle])} onSubmit={submit} > - {childrenWrapperWithProps(_.isFunction(children) ? children(inputValues) : children)} + {childrenWrapperWithProps(_.isFunction(children) ? children({inputValues}) : children)} {props.isSubmitButtonVisible && ( Date: Fri, 26 May 2023 01:42:47 +0300 Subject: [PATCH 318/751] Fix automatic authentication with magic link. --- src/libs/actions/Session/index.js | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/libs/actions/Session/index.js b/src/libs/actions/Session/index.js index 7f18d2861a35..0f26bb2a22da 100644 --- a/src/libs/actions/Session/index.js +++ b/src/libs/actions/Session/index.js @@ -455,17 +455,19 @@ function signInWithValidateCode(accountID, code, twoFactorAuthCode, preferredLoc }, ]; - API.write( - 'SigninUserWithLink', - { - accountID, - validateCode, - twoFactorAuthCode, - preferredLocale, - deviceInfo: getDeviceInfoForLogin(), - }, - {optimisticData, successData, failureData}, - ); + const params = { + accountID, + validateCode, + twoFactorAuthCode, + preferredLocale, + deviceInfo: getDeviceInfoForLogin(), + }; + + // Pass twoFactorAuthCode to sever only if it has a valid value, otherwise php might convert it to "null" as a string. + if (twoFactorAuthCode) { + params.twoFactorAuthCode = twoFactorAuthCode; + } + API.write('SigninUserWithLink', params, {optimisticData, successData, failureData}); } function signInWithValidateCodeAndNavigate(accountID, validateCode, twoFactorAuthCode, preferredLocale = CONST.LOCALES.DEFAULT) { From 8b91110907e77632877e802844f7e81e1dae4202 Mon Sep 17 00:00:00 2001 From: situchan Date: Fri, 26 May 2023 00:02:17 +0100 Subject: [PATCH 319/751] fix left part of conditional rendering not boolean on SigninPage, TaskHeader components --- src/components/TaskHeader.js | 3 ++- src/pages/signin/SignInPage.js | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/components/TaskHeader.js b/src/components/TaskHeader.js index 4b21d5a2ebe5..4c02cc8b3ab2 100644 --- a/src/components/TaskHeader.js +++ b/src/components/TaskHeader.js @@ -2,6 +2,7 @@ import React, {useEffect} from 'react'; import {View, TouchableOpacity} from 'react-native'; import PropTypes from 'prop-types'; import lodashGet from 'lodash/get'; +import _ from 'underscore'; import reportPropTypes from '../pages/reportPropTypes'; import withLocalize, {withLocalizePropTypes} from './withLocalize'; import * as ReportUtils from '../libs/ReportUtils'; @@ -54,7 +55,7 @@ function TaskHeader(props) { > - {props.report.managerEmail && ( + {!_.isEmpty(props.report.managerEmail) && ( <> Date: Fri, 26 May 2023 01:03:21 +0200 Subject: [PATCH 320/751] update QRCode logo propType --- src/components/QRCode/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/QRCode/index.js b/src/components/QRCode/index.js index 0cbde99d8c2e..06503d5987e7 100644 --- a/src/components/QRCode/index.js +++ b/src/components/QRCode/index.js @@ -10,7 +10,7 @@ const propTypes = { url: PropTypes.string.isRequired, /** * The logo which will be displayed in the middle of the QR code. - * Follows ImageProps href from react-native-svg that used by react-native-qrcode-svg. + * Follows ImageProps href from react-native-svg that is used by react-native-qrcode-svg. */ logo: PropTypes.oneOfType([PropTypes.shape({uri: PropTypes.string}), PropTypes.number, PropTypes.string]), /** From 693c385d6adc968714bc56bc35a98e7a393e0dc5 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Fri, 26 May 2023 02:08:28 +0300 Subject: [PATCH 321/751] Remove twoFactorAuthCode from params whrn null. --- src/libs/actions/Session/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/actions/Session/index.js b/src/libs/actions/Session/index.js index 0f26bb2a22da..d35c1ae6f366 100644 --- a/src/libs/actions/Session/index.js +++ b/src/libs/actions/Session/index.js @@ -458,7 +458,6 @@ function signInWithValidateCode(accountID, code, twoFactorAuthCode, preferredLoc const params = { accountID, validateCode, - twoFactorAuthCode, preferredLocale, deviceInfo: getDeviceInfoForLogin(), }; From 9e7682065ed9cd07b87d0bffb1bc015108548622 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Fri, 26 May 2023 02:25:44 +0300 Subject: [PATCH 322/751] Update src/libs/actions/Session/index.js Co-authored-by: Rajat Parashar --- src/libs/actions/Session/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/Session/index.js b/src/libs/actions/Session/index.js index d35c1ae6f366..6143c39090a7 100644 --- a/src/libs/actions/Session/index.js +++ b/src/libs/actions/Session/index.js @@ -462,7 +462,7 @@ function signInWithValidateCode(accountID, code, twoFactorAuthCode, preferredLoc deviceInfo: getDeviceInfoForLogin(), }; - // Pass twoFactorAuthCode to sever only if it has a valid value, otherwise php might convert it to "null" as a string. + // Pass twoFactorAuthCode to server only if it has a valid value, otherwise php might convert it to "null" as a string. if (twoFactorAuthCode) { params.twoFactorAuthCode = twoFactorAuthCode; } From af826f12b3505b73303ccfc1731f355e0e410cbe Mon Sep 17 00:00:00 2001 From: Sibtain Ali Date: Fri, 26 May 2023 05:42:14 +0500 Subject: [PATCH 323/751] feat: allow chatReportSelector to return the object for IOU reports --- src/pages/home/sidebar/SidebarLinks.js | 48 +++++++++++--------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/src/pages/home/sidebar/SidebarLinks.js b/src/pages/home/sidebar/SidebarLinks.js index d48ca795a3e8..4bf4279b51cf 100644 --- a/src/pages/home/sidebar/SidebarLinks.js +++ b/src/pages/home/sidebar/SidebarLinks.js @@ -220,33 +220,27 @@ SidebarLinks.defaultProps = defaultProps; * @param {Object} [report] * @returns {Object|undefined} */ -const chatReportSelector = (report) => { - if (ReportUtils.isIOUReport(report)) { - return null; - } - return ( - report && { - reportID: report.reportID, - participants: report.participants, - hasDraft: report.hasDraft, - isPinned: report.isPinned, - errorFields: { - addWorkspaceRoom: report.errorFields && report.errorFields.addWorkspaceRoom, - }, - lastReadTime: report.lastReadTime, - lastMentionedTime: report.lastMentionedTime, - lastMessageText: report.lastMessageText, - lastVisibleActionCreated: report.lastVisibleActionCreated, - iouReportID: report.iouReportID, - hasOutstandingIOU: report.hasOutstandingIOU, - statusNum: report.statusNum, - stateNum: report.stateNum, - chatType: report.chatType, - policyID: report.policyID, - reportName: report.reportName, - } - ); -}; +const chatReportSelector = (report) => + report && { + reportID: report.reportID, + participants: report.participants, + hasDraft: report.hasDraft, + isPinned: report.isPinned, + errorFields: { + addWorkspaceRoom: report.errorFields && report.errorFields.addWorkspaceRoom, + }, + lastReadTime: report.lastReadTime, + lastMentionedTime: report.lastMentionedTime, + lastMessageText: report.lastMessageText, + lastVisibleActionCreated: report.lastVisibleActionCreated, + iouReportID: report.iouReportID, + hasOutstandingIOU: report.hasOutstandingIOU, + statusNum: report.statusNum, + stateNum: report.stateNum, + chatType: report.chatType, + policyID: report.policyID, + reportName: report.reportName, + }; /** * @param {Object} [personalDetails] From 392845da213bbbf54d8aef305db4a5c73c109258 Mon Sep 17 00:00:00 2001 From: Thanos30 Date: Fri, 26 May 2023 04:00:43 +0300 Subject: [PATCH 324/751] Make sure reportRecepient --- src/pages/home/report/ReportActionCompose.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index c789b03ab0b9..d0ea092396f0 100644 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -929,7 +929,7 @@ class ReportActionCompose extends React.Component { style={this.props.isComposerFullSize ? styles.chatItemFullComposeRow : {}} contentContainerStyle={this.props.isComposerFullSize ? styles.flex1 : {}} > - {shouldShowReportRecipientLocalTime && } + {shouldShowReportRecipientLocalTime && !!reportRecipient && } Date: Thu, 25 May 2023 19:14:54 -0600 Subject: [PATCH 325/751] fix condition for isCheckingPublicRoom --- src/Expensify.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Expensify.js b/src/Expensify.js index d3119ecd7df5..b5243c555e74 100644 --- a/src/Expensify.js +++ b/src/Expensify.js @@ -99,7 +99,7 @@ function Expensify(props) { const [isSplashHidden, setIsSplashHidden] = useState(false); const isAuthenticated = useMemo(() => Boolean(lodashGet(props.session, 'authToken', null)), [props.session]); - const shouldInit = isNavigationReady && (!isAuthenticated || props.isSidebarLoaded || !props.isCheckingPublicRoom); + const shouldInit = isNavigationReady && (!isAuthenticated || props.isSidebarLoaded) && !props.isCheckingPublicRoom; const shouldHideSplash = shouldInit && !isSplashHidden; const initializeClient = () => { From c25bb74a7898e0023e5338e0628b8924b75f5acb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Ch=C3=A1vez?= Date: Thu, 25 May 2023 19:15:14 -0600 Subject: [PATCH 326/751] don't check the public room right after sign out --- src/libs/actions/SignInRedirect.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/actions/SignInRedirect.js b/src/libs/actions/SignInRedirect.js index 4d398b898318..a500635222d6 100644 --- a/src/libs/actions/SignInRedirect.js +++ b/src/libs/actions/SignInRedirect.js @@ -66,6 +66,7 @@ function resetHomeRouteParams() { }); Navigation.setParams(emptyParams, lodashGet(homeRoute, 'key', '')); + Onyx.set(ONYXKEYS.IS_CHECKING_PUBLIC_ROOM, false); }); } From f49a93eabed5980d4a42df74e775f3a6df8da3d7 Mon Sep 17 00:00:00 2001 From: Daniel Gale-Rosen Date: Thu, 25 May 2023 21:17:27 -0400 Subject: [PATCH 327/751] use constants for decisions --- src/CONST.js | 2 ++ src/pages/home/report/ReportActionItem.js | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/CONST.js b/src/CONST.js index 182548b4d99e..b89af0a998bb 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -2432,6 +2432,8 @@ const CONST = { MODERATION: { MODERATOR_DECISION_PENDING: 'pending', MODERATOR_DECISION_PENDING_HIDE: 'pendingHide', + MODERATOR_DECISION_APPROVED: 'approved', + MODERATOR_DECISION: 'hidden', FLAG_SEVERITY_SPAM: 'spam', FLAG_SEVERITY_INCONSIDERATE: 'inconsiderate', }, diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index 0093a0e15f5c..f2faeffcf2ec 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -107,7 +107,7 @@ const defaultProps = { function ReportActionItem(props) { const [isContextMenuActive, setIsContextMenuActive] = useState(ReportActionContextMenu.isActiveReportAction(props.action.reportActionID)); const [isHidden, setIsHidden] = useState(false); - const [moderationDecision, setModerationDecision] = useState('approved'); + const [moderationDecision, setModerationDecision] = useState(CONST.MODERATION.MODERATOR_DECISION_APPROVED); const textInputRef = useRef(); const popoverAnchorRef = useRef(); @@ -129,7 +129,7 @@ function ReportActionItem(props) { // Right now we are only sending the latest moderationDecision to the frontend even though it is an array const latestDecision = props.action.moderationDecisions[0]; - if (latestDecision.decision === 'pendingHide' || latestDecision.decision === 'hidden') { + if (latestDecision.decision === CONST.MODERATION.MODERATOR_DECISION_PENDING_HIDE || latestDecision.decision === CONST.MODERATION.MODERATOR_DECISION_HIDDEN) { setIsHidden(true); } setModerationDecision(latestDecision.decision); @@ -245,7 +245,7 @@ function ReportActionItem(props) { ); } else { const message = _.last(lodashGet(props.action, 'message', [{}])); - const hasBeenFlagged = moderationDecision !== 'approved'; + const hasBeenFlagged = moderationDecision !== CONST.MODERATION.MODERATOR_DECISION_APPROVED; const isAttachment = _.has(props.action, 'isAttachment') ? props.action.isAttachment : ReportUtils.isReportMessageAttachment(message); children = ( {content} From b5083eef6571d7f735f674c73432bf547d3fda3d Mon Sep 17 00:00:00 2001 From: Daniel Gale-Rosen Date: Thu, 25 May 2023 21:19:36 -0400 Subject: [PATCH 328/751] fix constant and prettier --- src/CONST.js | 2 +- src/pages/home/report/ReportActionItem.js | 28 +++++++++++++------ .../home/report/ReportActionItemMessage.js | 28 +++++++++++-------- .../home/report/ReportActionItemSingle.js | 4 +-- 4 files changed, 38 insertions(+), 24 deletions(-) diff --git a/src/CONST.js b/src/CONST.js index b89af0a998bb..969f451bc2ba 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -2433,7 +2433,7 @@ const CONST = { MODERATOR_DECISION_PENDING: 'pending', MODERATOR_DECISION_PENDING_HIDE: 'pendingHide', MODERATOR_DECISION_APPROVED: 'approved', - MODERATOR_DECISION: 'hidden', + MODERATOR_DECISION_HIDDEN: 'hidden', FLAG_SEVERITY_SPAM: 'spam', FLAG_SEVERITY_INCONSIDERATE: 'inconsiderate', }, diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index f2faeffcf2ec..febe993320a4 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -133,7 +133,7 @@ function ReportActionItem(props) { setIsHidden(true); } setModerationDecision(latestDecision.decision); - }, [props.action, moderationDecision]) + }, [props.action, moderationDecision]); const toggleContextMenuFromActiveReportAction = useCallback(() => { setIsContextMenuActive(ReportActionContextMenu.isActiveReportAction(props.action.reportActionID)); @@ -263,18 +263,25 @@ function ReportActionItem(props) { isHidden={isHidden} style={[ !props.displayAsGroup && isAttachment ? styles.mt2 : undefined, - _.contains([..._.values(CONST.REPORT.ACTIONS.TYPE.POLICYCHANGELOG), CONST.REPORT.ACTIONS.TYPE.IOU], props.action.actionName) ? styles.colorMuted : undefined, + _.contains([..._.values(CONST.REPORT.ACTIONS.TYPE.POLICYCHANGELOG), CONST.REPORT.ACTIONS.TYPE.IOU], props.action.actionName) + ? styles.colorMuted + : undefined, ]} /> - {props.displayAsGroup && hasBeenFlagged && + {props.displayAsGroup && hasBeenFlagged && ( - } + )} ) : ( )} - {!props.displayAsGroup && hasBeenFlagged && + {!props.displayAsGroup && hasBeenFlagged && ( - } + )} ); } diff --git a/src/pages/home/report/ReportActionItemMessage.js b/src/pages/home/report/ReportActionItemMessage.js index 8b93cd1668d3..4d6c0b8dfb30 100644 --- a/src/pages/home/report/ReportActionItemMessage.js +++ b/src/pages/home/report/ReportActionItemMessage.js @@ -28,18 +28,22 @@ const defaultProps = { const ReportActionItemMessage = (props) => ( - {!props.isHidden ? _.map(_.compact(props.action.previousMessage || props.action.message), (fragment, index) => ( - - )) : {props.translate('moderation.flaggedContent')}} + {!props.isHidden ? ( + _.map(_.compact(props.action.previousMessage || props.action.message), (fragment, index) => ( + + )) + ) : ( + {props.translate('moderation.flaggedContent')} + )} ); diff --git a/src/pages/home/report/ReportActionItemSingle.js b/src/pages/home/report/ReportActionItemSingle.js index 69e342e2aa08..5dac6fdb1cb3 100644 --- a/src/pages/home/report/ReportActionItemSingle.js +++ b/src/pages/home/report/ReportActionItemSingle.js @@ -133,9 +133,7 @@ const ReportActionItemSingle = (props) => { ) : null} - - {props.children} - + {props.children} ); From b104d9b78ab96f85f2b1dba86bdf753e9b11eafd Mon Sep 17 00:00:00 2001 From: Daniel Gale-Rosen Date: Thu, 25 May 2023 21:27:59 -0400 Subject: [PATCH 329/751] act normal for pending --- src/pages/home/report/ReportActionItem.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index febe993320a4..679d75df801a 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -245,7 +245,7 @@ function ReportActionItem(props) { ); } else { const message = _.last(lodashGet(props.action, 'message', [{}])); - const hasBeenFlagged = moderationDecision !== CONST.MODERATION.MODERATOR_DECISION_APPROVED; + const hasBeenFlagged = moderationDecision !== CONST.MODERATION.MODERATOR_DECISION_APPROVED && moderationDecision !== CONST.MODERATION.MODERATOR_DECISION_PENDING; const isAttachment = _.has(props.action, 'isAttachment') ? props.action.isAttachment : ReportUtils.isReportMessageAttachment(message); children = ( {content} From 5e9a8c85b9a8613dad132bf350221f6b1a64ecbd Mon Sep 17 00:00:00 2001 From: Daniel Gale-Rosen Date: Thu, 25 May 2023 21:48:50 -0400 Subject: [PATCH 330/751] remove unnecessary conditional --- src/pages/home/report/ReportActionItem.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index 679d75df801a..1423ceab7773 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -123,7 +123,7 @@ function ReportActionItem(props) { // Hide the message if it is being moderated for a higher offense, or is hidden by a moderator // Removed messages should not be shown anyway and should not need this flow useEffect(() => { - if (!props.action.moderationDecisions || _.isEmpty(props.action.moderationDecisions)) { + if (_.isEmpty(props.action.moderationDecisions)) { return; } From 975ba7f1108dc38b6c65baa662ff71fa0f3c1556 Mon Sep 17 00:00:00 2001 From: Hans Date: Fri, 26 May 2023 09:04:32 +0700 Subject: [PATCH 331/751] remove hard code with variables --- src/components/QRShare/index.js | 4 ++-- src/styles/styles.js | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/QRShare/index.js b/src/components/QRShare/index.js index c515a0dd4821..784e32d5410e 100644 --- a/src/components/QRShare/index.js +++ b/src/components/QRShare/index.js @@ -64,7 +64,7 @@ class QRShare extends Component { @@ -74,7 +74,7 @@ class QRShare extends Component { {this.props.subtitle && ( Date: Thu, 25 May 2023 22:10:24 -0400 Subject: [PATCH 332/751] add proptype comment --- src/pages/home/report/ReportActionItemMessage.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/home/report/ReportActionItemMessage.js b/src/pages/home/report/ReportActionItemMessage.js index 4d6c0b8dfb30..a764eafb84b7 100644 --- a/src/pages/home/report/ReportActionItemMessage.js +++ b/src/pages/home/report/ReportActionItemMessage.js @@ -15,6 +15,7 @@ const propTypes = { /** Additional styles to add after local styles. */ style: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]), + /** Whether or not the message is hidden by moderation */ isHidden: PropTypes.bool, /** localization props */ From b81f4a55d494ddff0e718bd1ce72ed10c4e113da Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Fri, 26 May 2023 10:12:39 +0800 Subject: [PATCH 333/751] bypass policyRooms beta when trying to access policy rooms --- src/libs/ReportUtils.js | 4 ---- src/pages/home/ReportScreen.js | 6 ++---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 408e3325bdc5..1b3740bea60c 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1940,10 +1940,6 @@ function shouldReportBeInOptionList(report, reportIDFromRoute, isInGSDMode, curr return false; } - if (isUserCreatedPolicyRoom(report) && !Permissions.canUsePolicyRooms(betas)) { - return false; - } - // Include the currently viewed report. If we excluded the currently viewed report, then there // would be no way to highlight it in the options list and it would be confusing to users because they lose // a sense of context. diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index 223606dc30c3..2db682a776ee 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -231,10 +231,8 @@ class ReportScreen extends React.Component { // There are no reportActions at all to display and we are still in the process of loading the next set of actions. const isLoadingInitialReportActions = _.isEmpty(this.props.reportActions) && this.props.report.isLoadingReportActions; - // Users not in the Default Room or Policy Room Betas can't view the report - const shouldHideReport = - (ReportUtils.isDefaultRoom(this.props.report) && !ReportUtils.canSeeDefaultRoom(this.props.report, this.props.policies, this.props.betas)) || - (ReportUtils.isUserCreatedPolicyRoom(this.props.report) && !Permissions.canUsePolicyRooms(this.props.betas)); + // We hide default rooms (it's basically just domain rooms now) from people who aren't on the defaultRooms beta. + const shouldHideReport = ReportUtils.isDefaultRoom(this.props.report) && !ReportUtils.canSeeDefaultRoom(this.props.report, this.props.policies, this.props.betas); // When the ReportScreen is not open/in the viewport, we want to "freeze" it for performance reasons const shouldFreeze = this.props.isSmallScreenWidth && this.props.isDrawerOpen; From 018ef3c8b6322021d737a30755ac9a65c7833258 Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Fri, 26 May 2023 10:19:28 +0800 Subject: [PATCH 334/751] fix tests --- src/libs/Permissions.js | 1 + tests/unit/SidebarFilterTest.js | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libs/Permissions.js b/src/libs/Permissions.js index 84d0a3d0154b..f46b74648b46 100644 --- a/src/libs/Permissions.js +++ b/src/libs/Permissions.js @@ -75,6 +75,7 @@ function canUseCommentLinking(betas) { * @returns {Boolean} */ function canUsePolicyRooms(betas) { + return false; return _.contains(betas, CONST.BETAS.POLICY_ROOMS) || _.contains(betas, CONST.BETAS.ALL); } diff --git a/tests/unit/SidebarFilterTest.js b/tests/unit/SidebarFilterTest.js index 46dc73d17320..0c6bc75f5e68 100644 --- a/tests/unit/SidebarFilterTest.js +++ b/tests/unit/SidebarFilterTest.js @@ -130,11 +130,11 @@ describe('Sidebar', () => { }), ) - // Then no reports are rendered in the LHN + // Then the report appears in the LHN .then(() => { const hintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); const optionRows = screen.queryAllByAccessibilityHint(hintText); - expect(optionRows).toHaveLength(0); + expect(optionRows).toHaveLength(1); }) // When the user is added to the policy rooms beta and the sidebar re-renders @@ -144,7 +144,7 @@ describe('Sidebar', () => { }), ) - // Then there is one report rendered in the LHN + // Then the report is still rendered in the LHN .then(() => { const hintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); const optionRows = screen.queryAllByAccessibilityHint(hintText); From 1bacc582f67ad6be9425ef55d50998152b3d79bf Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Fri, 26 May 2023 10:19:55 +0800 Subject: [PATCH 335/751] undo unused --- src/libs/Permissions.js | 1 - src/pages/home/ReportScreen.js | 1 - 2 files changed, 2 deletions(-) diff --git a/src/libs/Permissions.js b/src/libs/Permissions.js index f46b74648b46..84d0a3d0154b 100644 --- a/src/libs/Permissions.js +++ b/src/libs/Permissions.js @@ -75,7 +75,6 @@ function canUseCommentLinking(betas) { * @returns {Boolean} */ function canUsePolicyRooms(betas) { - return false; return _.contains(betas, CONST.BETAS.POLICY_ROOMS) || _.contains(betas, CONST.BETAS.ALL); } diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index 2db682a776ee..7d9c363273ef 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -13,7 +13,6 @@ import Navigation from '../../libs/Navigation/Navigation'; import ROUTES from '../../ROUTES'; import * as Report from '../../libs/actions/Report'; import ONYXKEYS from '../../ONYXKEYS'; -import Permissions from '../../libs/Permissions'; import * as ReportUtils from '../../libs/ReportUtils'; import ReportActionsView from './report/ReportActionsView'; import CONST from '../../CONST'; From e5d62dc3c6353c15486098a808779774792c7637 Mon Sep 17 00:00:00 2001 From: Hans Date: Fri, 26 May 2023 09:34:24 +0700 Subject: [PATCH 336/751] fix linting --- src/styles/styles.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/styles/styles.js b/src/styles/styles.js index b2d491a5ee26..6d57a2332345 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -3311,7 +3311,7 @@ const styles = { fontWeight: fontWeightBold, lineHeight: undefined, }, - + expensifyQrLogo: { alignSelf: 'stretch', height: 27, From 54f36fb9850ed83292e50f66db0c8e84d2e14e87 Mon Sep 17 00:00:00 2001 From: tienifr Date: Fri, 26 May 2023 11:10:06 +0700 Subject: [PATCH 337/751] fix: add actorEmail to optimistic data --- src/libs/actions/Report.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index b8dda8a3d551..22a36e100fef 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -403,12 +403,12 @@ function openReport(reportID, participantList = [], newReportObject = {}, parent onyxData.optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${newReportObject.parentReportID}`, - value: {[parentReportActionID]: {childReportID: reportID}}, + value: {[parentReportActionID]: {childReportID: reportID, actorEmail: currentUserEmail}}, }); onyxData.failureData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${newReportObject.parentReportID}`, - value: {[parentReportActionID]: {childReportID: '0'}}, + value: {[parentReportActionID]: {childReportID: '0', actorEmail: currentUserEmail}}, }); } } From d2ac397ec70c0d28b4d7d955cfb6b9be4433faf8 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Fri, 26 May 2023 11:13:09 +0700 Subject: [PATCH 338/751] fix: update height for text container --- src/components/MagicCodeInput.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/MagicCodeInput.js b/src/components/MagicCodeInput.js index 30c9b9ad4d9d..13fca0f735e6 100644 --- a/src/components/MagicCodeInput.js +++ b/src/components/MagicCodeInput.js @@ -293,7 +293,7 @@ function MagicCodeInput(props) { key={index} style={[styles.w15]} > - + {decomposeString(props.value, props.maxLength)[index] || ''} From f190a8fb8456e6a55ed4ee0686a89f34dd651de7 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Fri, 26 May 2023 11:44:27 +0700 Subject: [PATCH 339/751] fix: lint --- src/components/MagicCodeInput.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/components/MagicCodeInput.js b/src/components/MagicCodeInput.js index 13fca0f735e6..dbe414e95a14 100644 --- a/src/components/MagicCodeInput.js +++ b/src/components/MagicCodeInput.js @@ -293,7 +293,14 @@ function MagicCodeInput(props) { key={index} style={[styles.w15]} > - + {decomposeString(props.value, props.maxLength)[index] || ''} From 476ee303bf1e47fe0a2d98bbf54836eb68092a4d Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Fri, 26 May 2023 14:10:11 +0800 Subject: [PATCH 340/751] remove unnecessary clone and ref --- src/components/Tooltip/index.js | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/components/Tooltip/index.js b/src/components/Tooltip/index.js index 5ec44447cf2d..5403cf3055b1 100644 --- a/src/components/Tooltip/index.js +++ b/src/components/Tooltip/index.js @@ -120,18 +120,6 @@ class Tooltip extends PureComponent { throw Error('Children is not a valid element.'); } - const target = React.cloneElement(React.Children.only(this.props.children), { - ref: (el) => { - this.wrapperView = el; - - // Call the original ref, if any - const {ref} = this.props.children; - if (_.isFunction(ref)) { - ref(el); - } - }, - }); - return ( <> {this.state.isRendered && ( @@ -161,7 +149,7 @@ class Tooltip extends PureComponent { onHoverIn={this.showTooltip} onHoverOut={this.hideTooltip} > - {target} + {React.Children.only(this.props.children)} From e7ab1510288c07eb8cef7266d7a68369fd03c385 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Fri, 26 May 2023 14:10:37 +0800 Subject: [PATCH 341/751] handle ref object --- src/components/Hoverable/index.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/components/Hoverable/index.js b/src/components/Hoverable/index.js index d6dd14679ecd..c3b26d674f86 100644 --- a/src/components/Hoverable/index.js +++ b/src/components/Hoverable/index.js @@ -82,6 +82,11 @@ class Hoverable extends Component { const {ref} = child; if (_.isFunction(ref)) { ref(el); + return; + } + + if (_.isObject(ref)) { + ref.current = el; } }, onMouseEnter: (el) => { From e5f1d5ee155f68cd7875095d3c27c48236cd17db Mon Sep 17 00:00:00 2001 From: OSBotify Date: Fri, 26 May 2023 06:32:17 +0000 Subject: [PATCH 342/751] Update version to 1.3.19-0 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 4 ++-- ios/NewExpensifyTests/Info.plist | 4 ++-- package-lock.json | 4 ++-- package.json | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 2c114b067d69..fc0f1a28988d 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -106,8 +106,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001031802 - versionName "1.3.18-2" + versionCode 1001031900 + versionName "1.3.19-0" } splits { diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 7e5b6066cf7f..0bd788275429 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.3.18 + 1.3.19 CFBundleSignature ???? CFBundleURLTypes @@ -30,7 +30,7 @@ CFBundleVersion - 1.3.18.2 + 1.3.19.0 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index e18ab55f7e01..4eab2113c161 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.3.18 + 1.3.19 CFBundleSignature ???? CFBundleVersion - 1.3.18.2 + 1.3.19.0 diff --git a/package-lock.json b/package-lock.json index cfefaaa56b0b..427306b70486 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.3.18-2", + "version": "1.3.19-0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.3.18-2", + "version": "1.3.19-0", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 037a717cb02f..0d0bc54ff524 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.3.18-2", + "version": "1.3.19-0", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From ce632161ae63e68c68a55b93b0f3f8f1d5a2e505 Mon Sep 17 00:00:00 2001 From: Hans Date: Fri, 26 May 2023 13:35:07 +0700 Subject: [PATCH 343/751] Fix overlay divider line --- src/pages/home/report/ReportActionItemParentAction.js | 6 +++++- src/pages/home/report/ReportActionsList.js | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionItemParentAction.js b/src/pages/home/report/ReportActionItemParentAction.js index cc50b62a1774..2d5580305be5 100644 --- a/src/pages/home/report/ReportActionItemParentAction.js +++ b/src/pages/home/report/ReportActionItemParentAction.js @@ -17,6 +17,9 @@ import reportActionPropTypes from './reportActionPropTypes'; import * as ReportActionsUtils from '../../../libs/ReportActionsUtils'; const propTypes = { + /** Flag to show, hide the thread divider line */ + shouldHideThreadDividerLine: PropTypes.bool, + /** The id of the report */ reportID: PropTypes.string.isRequired, @@ -38,6 +41,7 @@ const propTypes = { const defaultProps = { report: {}, parentReportActions: {}, + shouldHideThreadDividerLine: false, }; const ReportActionItemParentAction = (props) => { @@ -67,7 +71,7 @@ const ReportActionItemParentAction = (props) => { /> )} - + {!props.shouldHideThreadDividerLine && } ); }; diff --git a/src/pages/home/report/ReportActionsList.js b/src/pages/home/report/ReportActionsList.js index 1a3b44c3f806..f601cb83a5fa 100644 --- a/src/pages/home/report/ReportActionsList.js +++ b/src/pages/home/report/ReportActionsList.js @@ -115,8 +115,12 @@ const ReportActionsList = (props) => { // When the new indicator should not be displayed we explicitly set it to null const shouldDisplayNewMarker = reportAction.reportActionID === newMarkerReportActionID; const shouldDisplayParentAction = reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED && ReportUtils.isThread(report); + // check if the second message of the thread is unread, then hide the divider line. + const shouldHideThreadDividerLine = shouldDisplayParentAction && sortedReportActions.length > 1 && + sortedReportActions[sortedReportActions.length -2].reportActionID === newMarkerReportActionID; return shouldDisplayParentAction ? ( From f688bf780ac2956c5f0342bf4864be9782e478ed Mon Sep 17 00:00:00 2001 From: Hans Date: Fri, 26 May 2023 13:49:24 +0700 Subject: [PATCH 344/751] fix linting --- src/pages/home/report/ReportActionsList.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/home/report/ReportActionsList.js b/src/pages/home/report/ReportActionsList.js index f601cb83a5fa..ff5f59c2c007 100644 --- a/src/pages/home/report/ReportActionsList.js +++ b/src/pages/home/report/ReportActionsList.js @@ -116,8 +116,8 @@ const ReportActionsList = (props) => { const shouldDisplayNewMarker = reportAction.reportActionID === newMarkerReportActionID; const shouldDisplayParentAction = reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED && ReportUtils.isThread(report); // check if the second message of the thread is unread, then hide the divider line. - const shouldHideThreadDividerLine = shouldDisplayParentAction && sortedReportActions.length > 1 && - sortedReportActions[sortedReportActions.length -2].reportActionID === newMarkerReportActionID; + const shouldHideThreadDividerLine = + shouldDisplayParentAction && sortedReportActions.length > 1 && sortedReportActions[sortedReportActions.length - 2].reportActionID === newMarkerReportActionID; return shouldDisplayParentAction ? ( Date: Fri, 26 May 2023 09:24:05 +0200 Subject: [PATCH 345/751] removed redundant comments, add JSDOc for PressableWithFeedback propTypes --- src/components/CalendarPicker/index.js | 8 ++------ src/components/Pressable/PressableWithFeedback.js | 10 ++++++++++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/components/CalendarPicker/index.js b/src/components/CalendarPicker/index.js index 52e0cbc7f2fc..7038d69d4b06 100644 --- a/src/components/CalendarPicker/index.js +++ b/src/components/CalendarPicker/index.js @@ -107,7 +107,6 @@ class CalendarPicker extends React.PureComponent { onPress={this.onYearPickerPressed} style={[styles.alignItemsCenter, styles.flexRow, styles.flex1, styles.justifyContentStart]} wrapperStyle={[styles.alignItemsCenter]} - // disable the opacity change on hover hoverDimmingValue={1} accessibilityLabel={this.props.translate('common.currentYear')} > @@ -132,7 +131,6 @@ class CalendarPicker extends React.PureComponent { testID="prev-month-arrow" disabled={!hasAvailableDatesPrevMonth} onPress={this.moveToPrevMonth} - // disable the opacity change on hover hoverDimmingValue={1} accessibilityLabel={this.props.translate('common.previous')} > @@ -145,7 +143,6 @@ class CalendarPicker extends React.PureComponent { testID="next-month-arrow" disabled={!hasAvailableDatesNextMonth} onPress={this.moveToNextMonth} - // disable the opacity change on hover hoverDimmingValue={1} accessibilityLabel={this.props.translate('common.next')} > @@ -182,9 +179,8 @@ class CalendarPicker extends React.PureComponent { onPress={() => this.onDayPressed(day)} style={styles.calendarDayRoot} accessibilityLabel={day ? day.toString() : undefined} - // disable focus and accessibility on empty fields - focusable={!!day} - accessible={!!day} + focusable={Boolean(day)} + accessible={Boolean(day)} > {({hovered, pressed}) => ( Date: Fri, 26 May 2023 09:35:32 +0200 Subject: [PATCH 346/751] remove measure --- .../PopoverReportActionContextMenu.js | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.js b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.js index 0e6ee25282a9..770968567139 100644 --- a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.js +++ b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.js @@ -232,28 +232,6 @@ class PopoverReportActionContextMenu extends React.Component { }); } - /** - * Used to calculate the Context Menu Dimensions - * - * @returns {JSX} - */ - measureContent() { - return ( - - ); - } - /** * Run the callback and return a noop function to reset it * @param {Function} callback From 03eae984c480f3ed329eae254a5220618704426e Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Fri, 26 May 2023 16:51:57 +0800 Subject: [PATCH 347/751] add shift vertical back --- src/components/AvatarCropModal/Slider.js | 5 ++++- src/components/EmojiPicker/CategoryShortcutButton.js | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/components/AvatarCropModal/Slider.js b/src/components/AvatarCropModal/Slider.js index cfa02a114eca..2877b3a9c917 100644 --- a/src/components/AvatarCropModal/Slider.js +++ b/src/components/AvatarCropModal/Slider.js @@ -49,7 +49,10 @@ const Slider = (props) => { > {tooltipIsVisible && ( - + )} diff --git a/src/components/EmojiPicker/CategoryShortcutButton.js b/src/components/EmojiPicker/CategoryShortcutButton.js index 738fa67ca274..567521637f19 100644 --- a/src/components/EmojiPicker/CategoryShortcutButton.js +++ b/src/components/EmojiPicker/CategoryShortcutButton.js @@ -33,7 +33,10 @@ class CategoryShortcutButton extends PureComponent { render() { return ( - + this.setState({isHighlighted: true})} From e8f0da36d6b1cda2b0eef5c7c04363bdc1906cdf Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Fri, 26 May 2023 16:53:05 +0800 Subject: [PATCH 348/751] improve overlapping element check for an element with border radius --- src/styles/getTooltipStyles.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/styles/getTooltipStyles.js b/src/styles/getTooltipStyles.js index 88c9845349ee..1d77ce1cddc5 100644 --- a/src/styles/getTooltipStyles.js +++ b/src/styles/getTooltipStyles.js @@ -57,14 +57,16 @@ function computeHorizontalShift(windowWidth, xOffset, componentWidth, tooltipWid * @param {Number} yOffset - The distance between the top edge of the window * and the top edge of the wrapped component. * @param {Element} [tooltip] - The reference to the tooltip's root element + * @param {Number} componentHeight - The height of the wrapped component. * @returns {Boolean} */ -function isOverlappingAtTop(xOffset, yOffset, tooltip) { +function isOverlappingAtTop(xOffset, yOffset, tooltip, componentHeight) { if (typeof document.elementFromPoint !== 'function') { return false; } - const element = document.elementFromPoint(xOffset, yOffset); + const centerY = yOffset + componentHeight / 2; + const element = document.elementFromPoint(xOffset, centerY); const tooltipRef = (tooltip && tooltip.current) || tooltip; // Ensure it's not the already rendered element of this very tooltip, so the tooltip doesn't try to "avoid" itself @@ -141,7 +143,7 @@ export default function getTooltipStyles( // If either a tooltip will try to render within GUTTER_WIDTH logical pixels of the top of the screen, // Or the wrapped component is overlapping at top-left with another element // we'll display it beneath its wrapped component rather than above it as usual. - shouldShowBelow = yOffset - tooltipHeight < GUTTER_WIDTH || isOverlappingAtTop(xOffset, yOffset, tooltip); + shouldShowBelow = yOffset - tooltipHeight < GUTTER_WIDTH || isOverlappingAtTop(xOffset, yOffset, tooltip, tooltipTargetHeight); // When the tooltip size is ready, we can start animating the scale. scale = currentSize; From c3d4f546c3a4fd63237516a3e544553ca65ce81f Mon Sep 17 00:00:00 2001 From: OSBotify Date: Fri, 26 May 2023 08:58:07 +0000 Subject: [PATCH 349/751] Update version to 1.3.19-1 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NewExpensifyTests/Info.plist | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index fc0f1a28988d..fb390da75cc1 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -106,8 +106,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001031900 - versionName "1.3.19-0" + versionCode 1001031901 + versionName "1.3.19-1" } splits { diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 0bd788275429..56471e6e70d0 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -30,7 +30,7 @@ CFBundleVersion - 1.3.19.0 + 1.3.19.1 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 4eab2113c161..4fa6f0550dc7 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.3.19.0 + 1.3.19.1 diff --git a/package-lock.json b/package-lock.json index 427306b70486..d448db9913b5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.3.19-0", + "version": "1.3.19-1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.3.19-0", + "version": "1.3.19-1", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 0d0bc54ff524..8bbf35dbe003 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.3.19-0", + "version": "1.3.19-1", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From 693ebe3d58d0f2bb7a5b2b9b82b26ace0fa92b8e Mon Sep 17 00:00:00 2001 From: Jules Rosser Date: Fri, 26 May 2023 10:48:49 +0100 Subject: [PATCH 350/751] further improvements to split bill details page --- src/ROUTES.js | 2 +- src/components/MoneyRequestConfirmationList.js | 15 ++++++--------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/ROUTES.js b/src/ROUTES.js index d22bb9400fc3..406a183d1f39 100644 --- a/src/ROUTES.js +++ b/src/ROUTES.js @@ -94,7 +94,7 @@ export default { getIouBillCurrencyRoute: (reportID, currency, backTo) => `${IOU_BILL_CURRENCY}/${reportID}?currency=${currency}&backTo=${backTo}`, getIouSendCurrencyRoute: (reportID, currency, backTo) => `${IOU_SEND_CURRENCY}/${reportID}?currency=${currency}&backTo=${backTo}`, SPLIT_BILL_DETAILS: `/:reportID/split/:reportActionID`, - getSplitBillDetailsRoute: (reportID, reportActionID) => `/${reportID}/split/${reportActionID}`, + getSplitBillDetailsRoute: (reportID, reportActionID) => `r/${reportID}/split/${reportActionID}`, getNewTaskRoute: (reportID) => `${NEW_TASK}/${reportID}`, NEW_TASK_WITH_REPORT_ID: `${NEW_TASK}/:reportID?`, TASK_TITLE: 'r/:reportID/title', diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index a76c728d0b8a..4e53f6967df0 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -89,7 +89,7 @@ const defaultProps = { selectedCurrencyCode: CONST.CURRENCY.USD, }, iouType: CONST.IOU.MONEY_REQUEST_TYPE.REQUEST, - payee: null, + payeePersonalDetails: null, canModifyParticipants: false, isReadOnly: false, bankAccountRoute: '', @@ -171,15 +171,12 @@ class MoneyRequestConfirmationList extends Component { } /** - * Returns the personalDetails object for the requester + * Returns the personalDetails object for the payee. Use the payee prop if passed, else fallback to current user * * @returns {Object} personalDetails */ - getRequestorPersonalDetails() { - if (this.props.payeePersonalDetails) { - return this.props.payeePersonalDetails; - } - return this.props.currentUserPersonalDetails; + getPayeePersonalDetails() { + return this.props.payeePersonalDetails || this.props.currentUserPersonalDetails; } /** @@ -199,7 +196,7 @@ class MoneyRequestConfirmationList extends Component { const myIOUAmount = IOUUtils.calculateAmount(selectedParticipants.length, this.props.iouAmount, true); const formattedPayeePersonalDetails = OptionsListUtils.getIOUConfirmationOptionsFromPayeePersonalDetail( - this.getRequestorPersonalDetails(), + this.getPayeePersonalDetails(), CurrencyUtils.convertToDisplayString(myIOUAmount, this.props.iou.selectedCurrencyCode), ); @@ -269,7 +266,7 @@ class MoneyRequestConfirmationList extends Component { return []; } const selectedParticipants = this.getSelectedParticipants(); - return [...selectedParticipants, OptionsListUtils.getIOUConfirmationOptionsFromPayeePersonalDetail(this.getRequestorPersonalDetails())]; + return [...selectedParticipants, OptionsListUtils.getIOUConfirmationOptionsFromPayeePersonalDetail(this.getPayeePersonalDetails())]; } /** From f2024d09f40094105c681482766a13b0db60a3b9 Mon Sep 17 00:00:00 2001 From: Jules Rosser Date: Fri, 26 May 2023 10:50:56 +0100 Subject: [PATCH 351/751] fix secondary route for split bill page --- src/ROUTES.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ROUTES.js b/src/ROUTES.js index 406a183d1f39..7e20bb7523f0 100644 --- a/src/ROUTES.js +++ b/src/ROUTES.js @@ -93,7 +93,7 @@ export default { getIouRequestCurrencyRoute: (reportID, currency, backTo) => `${IOU_REQUEST_CURRENCY}/${reportID}?currency=${currency}&backTo=${backTo}`, getIouBillCurrencyRoute: (reportID, currency, backTo) => `${IOU_BILL_CURRENCY}/${reportID}?currency=${currency}&backTo=${backTo}`, getIouSendCurrencyRoute: (reportID, currency, backTo) => `${IOU_SEND_CURRENCY}/${reportID}?currency=${currency}&backTo=${backTo}`, - SPLIT_BILL_DETAILS: `/:reportID/split/:reportActionID`, + SPLIT_BILL_DETAILS: `r/:reportID/split/:reportActionID`, getSplitBillDetailsRoute: (reportID, reportActionID) => `r/${reportID}/split/${reportActionID}`, getNewTaskRoute: (reportID) => `${NEW_TASK}/${reportID}`, NEW_TASK_WITH_REPORT_ID: `${NEW_TASK}/:reportID?`, From f2bf8008973c7331e5221839d6741ca8f317e614 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Ska=C5=82ka?= Date: Fri, 26 May 2023 11:54:40 +0200 Subject: [PATCH 352/751] migrated ReportActionItemCreated to PressableWithoutFeedback --- src/pages/home/report/ReportActionItemCreated.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/pages/home/report/ReportActionItemCreated.js b/src/pages/home/report/ReportActionItemCreated.js index 5fcda0903e75..a00e557ea613 100644 --- a/src/pages/home/report/ReportActionItemCreated.js +++ b/src/pages/home/report/ReportActionItemCreated.js @@ -1,5 +1,5 @@ import React from 'react'; -import {Pressable, View, Image} from 'react-native'; +import {View, Image} from 'react-native'; import lodashGet from 'lodash/get'; import {withOnyx} from 'react-native-onyx'; import PropTypes from 'prop-types'; @@ -17,6 +17,7 @@ import * as StyleUtils from '../../../styles/StyleUtils'; import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions'; import compose from '../../../libs/compose'; import withLocalize from '../../../components/withLocalize'; +import PressableWithoutFeedback from '../../../components/Pressable/PressableWithoutFeedback'; const propTypes = { /** The id of the report */ @@ -59,12 +60,14 @@ const ReportActionItemCreated = (props) => { accessibilityLabel={props.translate('accessibilityHints.chatWelcomeMessage')} style={[styles.p5, StyleUtils.getReportWelcomeTopMarginStyle(props.isSmallScreenWidth)]} > - ReportUtils.navigateToDetailsPage(props.report)} style={[styles.ph5, styles.pb3, styles.alignSelfStart]} + accessibilityLabel={props.translate('common.details')} + accessibilityRole="button" > - + From 388ea7dc8101bccf643fd06f7c19bf701f4058ad Mon Sep 17 00:00:00 2001 From: Sujit Kumar <60378235+therealsujitk@users.noreply.github.com> Date: Fri, 26 May 2023 15:26:16 +0530 Subject: [PATCH 353/751] Change shouldBlockSuggestionsCalc to a normal variable --- src/pages/home/report/ReportActionCompose.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index 31863b464f41..d5632b731bb6 100644 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -192,6 +192,9 @@ class ReportActionCompose extends React.Component { // prevent auto focus on existing chat for mobile device this.shouldFocusInputOnScreenFocus = canFocusInputOnScreenFocus(); + // This variable is used to decide whether to block the suggestions list from showing to prevent flickering + this.shouldBlockSuggestionsCalc = false; + this.state = { isFocused: this.shouldFocusInputOnScreenFocus && !this.props.modal.isVisible && !this.props.modal.willAlertModalBecomeVisible && this.props.shouldShowComposeInput, isFullComposerAvailable: props.isComposerFullSize, @@ -273,16 +276,16 @@ class ReportActionCompose extends React.Component { } onSelectionChange(e) { + if (this.shouldBlockSuggestionsCalc) { + this.setShouldBlockSuggestionsCalcToFalse(); + return; + } LayoutAnimation.configureNext(LayoutAnimation.create(50, LayoutAnimation.Types.easeInEaseOut, LayoutAnimation.Properties.opacity)); this.setState({selection: e.nativeEvent.selection}); if (!this.state.value || e.nativeEvent.selection.end < 1) { this.resetSuggestions(); return; } - if (this.state.shouldBlockSuggestionsCalc) { - this.setShouldBlockSuggestionsCalcToFalse(); - return; - } this.calculateEmojiSuggestion(); this.calculateMentionSuggestion(); } @@ -297,7 +300,6 @@ class ReportActionCompose extends React.Component { atSignIndex: -1, shouldShowEmojiSuggestionMenu: false, shouldShowMentionSuggestionMenu: false, - shouldBlockSuggestionsCalc: false, mentionPrefix: '', isAutoSuggestionPickerLarge: false, }; @@ -422,9 +424,7 @@ class ReportActionCompose extends React.Component { // eslint-disable-next-line rulesdir/prefer-early-return setShouldBlockSuggestionsCalcToFalse() { - if (this.state && this.state.shouldBlockSuggestionsCalc) { - this.setState({shouldBlockSuggestionsCalc: false}); - } + this.shouldBlockSuggestionsCalc = false; } /** @@ -1021,7 +1021,7 @@ class ReportActionCompose extends React.Component { // Set a flag to block emoji calculation until we're finished using the file picker, // which will stop any flickering as the file picker opens on non-native devices. if (this.willBlurTextInputOnTapOutside) { - this.setState({shouldBlockSuggestionsCalc: true}); + this.shouldBlockSuggestionsCalc = true; } openPicker({ From bdde009b3a3ce05cb8a9818dea286758d9fc17a0 Mon Sep 17 00:00:00 2001 From: Sujit Kumar <60378235+therealsujitk@users.noreply.github.com> Date: Fri, 26 May 2023 15:28:16 +0530 Subject: [PATCH 354/751] Fix suggestions list issues with mWeb --- src/pages/home/report/ReportActionCompose.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index d5632b731bb6..2a562a7c51d8 100644 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -1075,7 +1075,7 @@ class ReportActionCompose extends React.Component { this.setIsFocused(false); this.resetSuggestions(); }} - onClick={this.setShouldBlockSuggestionsCalcToFalse} + onMouseDown={this.setShouldBlockSuggestionsCalcToFalse} onPasteFile={displayFileInModal} shouldClear={this.state.textInputShouldClear} onClear={() => this.setTextInputShouldClear(false)} From 3a549e6b238d98e1e41824f66c28233b136292ea Mon Sep 17 00:00:00 2001 From: PrashantKumar Mangukiya Date: Fri, 26 May 2023 16:15:04 +0530 Subject: [PATCH 355/751] Handle very long title --- src/components/MenuItem.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/MenuItem.js b/src/components/MenuItem.js index 4c4aa97e94c0..586ea1f7456c 100644 --- a/src/components/MenuItem.js +++ b/src/components/MenuItem.js @@ -69,6 +69,7 @@ const MenuItem = (props) => { const descriptionVerticalMargin = props.shouldShowDescriptionOnTop ? styles.mb1 : styles.mt1; const titleTextStyle = StyleUtils.combineStyles( [ + styles.flexShrink1, styles.popoverMenuText, props.icon ? styles.ml3 : undefined, props.shouldShowBasicTitle ? undefined : styles.textStrong, From a26441a9cdeb28a09a27f6e455c631f1cb8b4ace Mon Sep 17 00:00:00 2001 From: Sujit Kumar <60378235+therealsujitk@users.noreply.github.com> Date: Fri, 26 May 2023 16:53:57 +0530 Subject: [PATCH 356/751] Manually call onSelectionChange onClick --- src/pages/home/report/ReportActionCompose.js | 23 ++++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index f8fe64818673..a5cc77136d4f 100644 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -284,16 +284,22 @@ class ReportActionCompose extends React.Component { } onSelectionChange(e) { + LayoutAnimation.configureNext(LayoutAnimation.create(50, LayoutAnimation.Types.easeInEaseOut, LayoutAnimation.Properties.opacity)); + + if (e) { + this.setState({selection: e.nativeEvent.selection}); + if (!this.state.value || e.nativeEvent.selection.end < 1) { + this.resetSuggestions(); + this.setShouldBlockSuggestionsCalcToFalse(); + return; + } + } + if (this.shouldBlockSuggestionsCalc) { this.setShouldBlockSuggestionsCalcToFalse(); return; } - LayoutAnimation.configureNext(LayoutAnimation.create(50, LayoutAnimation.Types.easeInEaseOut, LayoutAnimation.Properties.opacity)); - this.setState({selection: e.nativeEvent.selection}); - if (!this.state.value || e.nativeEvent.selection.end < 1) { - this.resetSuggestions(); - return; - } + this.calculateEmojiSuggestion(); this.calculateMentionSuggestion(); } @@ -1083,7 +1089,10 @@ class ReportActionCompose extends React.Component { this.setIsFocused(false); this.resetSuggestions(); }} - onMouseDown={this.setShouldBlockSuggestionsCalcToFalse} + onClick={() => { + this.setShouldBlockSuggestionsCalcToFalse(); + this.onSelectionChange(); + }} onPasteFile={displayFileInModal} shouldClear={this.state.textInputShouldClear} onClear={() => this.setTextInputShouldClear(false)} From a1cdc24ee5103d403749717c57e9694ace6fb342 Mon Sep 17 00:00:00 2001 From: tienifr Date: Fri, 26 May 2023 18:54:30 +0700 Subject: [PATCH 357/751] add isInputAutoFilled function --- src/libs/isInputAutofilled.js | 11 +++++++++++ src/pages/signin/LoginForm.js | 3 ++- 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 src/libs/isInputAutofilled.js diff --git a/src/libs/isInputAutofilled.js b/src/libs/isInputAutofilled.js new file mode 100644 index 000000000000..56fda5ce477e --- /dev/null +++ b/src/libs/isInputAutofilled.js @@ -0,0 +1,11 @@ +/** + * Check the input is auto filled or not + * @param {Object} input + * @return {Boolean} + */ +function isInputAutoFilled(input) { + if (!input.matches) return false; + return input.matches(':-webkit-autofill') || input.matches(':autofill'); +} + +export default isInputAutoFilled; diff --git a/src/pages/signin/LoginForm.js b/src/pages/signin/LoginForm.js index 437612908081..154efb3b56e0 100755 --- a/src/pages/signin/LoginForm.js +++ b/src/pages/signin/LoginForm.js @@ -24,6 +24,7 @@ import * as ErrorUtils from '../../libs/ErrorUtils'; import DotIndicatorMessage from '../../components/DotIndicatorMessage'; import * as CloseAccount from '../../libs/actions/CloseAccount'; import CONST from '../../CONST'; +import isInputAutoFilled from '../../libs/isInputAutoFilled'; const propTypes = { /** Should we dismiss the keyboard when transitioning away from the page? */ @@ -113,7 +114,7 @@ class LoginForm extends React.Component { } // Clear the "Account successfully closed" message when the user starts typing - if (this.props.closeAccount.success) { + if (this.props.closeAccount.success && !isInputAutoFilled(this.input)) { CloseAccount.setDefaultData(); } } From 1e91f93eeac7e85557b2d01894c0d08763d6590b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Ska=C5=82ka?= Date: Fri, 26 May 2023 14:00:32 +0200 Subject: [PATCH 358/751] migrate ModalHeader to PressableWithFeedback --- src/pages/iou/ModalHeader.js | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/pages/iou/ModalHeader.js b/src/pages/iou/ModalHeader.js index dd5b3fdadf54..30556dae86c1 100644 --- a/src/pages/iou/ModalHeader.js +++ b/src/pages/iou/ModalHeader.js @@ -1,5 +1,5 @@ import React from 'react'; -import {View, TouchableOpacity} from 'react-native'; +import {View} from 'react-native'; import PropTypes from 'prop-types'; import styles from '../../styles/styles'; import Icon from '../../components/Icon'; @@ -8,6 +8,7 @@ import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize import * as Expensicons from '../../components/Icon/Expensicons'; import Tooltip from '../../components/Tooltip'; import Navigation from '../../libs/Navigation/Navigation'; +import PressableWithFeedback from '../../components/Pressable/PressableWithFeedback'; const propTypes = { /** Title of the header */ @@ -32,25 +33,33 @@ const ModalHeader = (props) => ( {props.shouldShowBackButton && ( - - + )}
- Navigation.dismissModal()} style={[styles.touchableButtonImage]} accessibilityRole="button" accessibilityLabel={props.translate('common.close')} + // disable hover dim for switch + hoverDimmingValue={1} + pressDimmingValue={0.2} > - + From 08e021f31250ba81e854824044adeca7ccc1ee2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czernek?= Date: Fri, 26 May 2023 14:16:08 +0200 Subject: [PATCH 359/751] Prettier ignore instead of running prettier only on *.js files --- .prettierignore | 13 +++++++++++++ package.json | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/.prettierignore b/.prettierignore index 5cad6e04b900..01419fde288c 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,4 +1,17 @@ # The GH actions don't seem to compile and verify themselves well when Prettier is applied to them .github/actions/javascript/**/index.js +.well-known desktop/dist/**/*.js dist/**/*.js +assets/animations +android +ios +vendor +package.json +package-lock.json +*.html +*.yml +*.yaml +*.css +*.scss +*.md \ No newline at end of file diff --git a/package.json b/package.json index 8bbf35dbe003..8237c7bc3019 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "lint": "eslint . --max-warnings=0 --cache --cache-location=node_modules/.cache/eslint", "lint-watch": "npx eslint-watch --watch --changed", "shellcheck": "./scripts/shellCheck.sh", - "prettier": "prettier --write \"**/*.js\"", + "prettier": "prettier --write .", "prettier-watch": "onchange \"**/*.js\" -- prettier --write --ignore-unknown {{changed}}", "print-version": "echo $npm_package_version", "storybook": "start-storybook -p 6006", From 6e4dbfae815bd36912e195b19166123c7252c5ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czernek?= Date: Fri, 26 May 2023 14:23:41 +0200 Subject: [PATCH 360/751] Format according to prettier config. --- tests/unit/currencyList.json | 1090 +++++++++++++++++----------------- 1 file changed, 545 insertions(+), 545 deletions(-) diff --git a/tests/unit/currencyList.json b/tests/unit/currencyList.json index c6eda7bdd766..1242509c0813 100644 --- a/tests/unit/currencyList.json +++ b/tests/unit/currencyList.json @@ -1,875 +1,875 @@ { "AED": { - "symbol": "Dhs", - "name": "UAE Dirham", - "ISO4217": "784" + "symbol": "Dhs", + "name": "UAE Dirham", + "ISO4217": "784" }, "AFN": { - "symbol": "Af", - "name": "Afghan Afghani", - "decimals": 0, - "ISO4217": "971" + "symbol": "Af", + "name": "Afghan Afghani", + "decimals": 0, + "ISO4217": "971" }, "ALL": { - "symbol": "ALL", - "name": "Albanian Lek", - "decimals": 0, - "ISO4217": "008" + "symbol": "ALL", + "name": "Albanian Lek", + "decimals": 0, + "ISO4217": "008" }, "AMD": { - "symbol": "դր", - "name": "Armenian Dram", - "ISO4217": "051" + "symbol": "դր", + "name": "Armenian Dram", + "ISO4217": "051" }, "ANG": { - "symbol": "NAƒ", - "name": "Neth Antilles Guilder", - "ISO4217": "532" + "symbol": "NAƒ", + "name": "Neth Antilles Guilder", + "ISO4217": "532" }, "AOA": { - "symbol": "Kz", - "name": "Angolan Kwanza", - "ISO4217": "973" + "symbol": "Kz", + "name": "Angolan Kwanza", + "ISO4217": "973" }, "ARS": { - "symbol": "AR$", - "name": "Argentine Peso", - "ISO4217": "032" + "symbol": "AR$", + "name": "Argentine Peso", + "ISO4217": "032" }, "AUD": { - "symbol": "A$", - "name": "Australian Dollar", - "ISO4217": "036" + "symbol": "A$", + "name": "Australian Dollar", + "ISO4217": "036" }, "AWG": { - "symbol": "ƒ", - "name": "Aruba Florin", - "ISO4217": "533" + "symbol": "ƒ", + "name": "Aruba Florin", + "ISO4217": "533" }, "AZN": { - "symbol": "man", - "name": "Azerbaijani Manat", - "ISO4217": "944" + "symbol": "man", + "name": "Azerbaijani Manat", + "ISO4217": "944" }, "BAM": { - "symbol": "KM", - "name": "Bosnia And Herzegovina Convertible Mark", - "ISO4217": "977" + "symbol": "KM", + "name": "Bosnia And Herzegovina Convertible Mark", + "ISO4217": "977" }, "BBD": { - "symbol": "Bds$", - "name": "Barbados Dollar", - "ISO4217": "052" + "symbol": "Bds$", + "name": "Barbados Dollar", + "ISO4217": "052" }, "BDT": { - "symbol": "Tk", - "name": "Bangladesh Taka", - "ISO4217": "050" + "symbol": "Tk", + "name": "Bangladesh Taka", + "ISO4217": "050" }, "BGN": { - "symbol": "лв", - "name": "Bulgarian Lev", - "ISO4217": "975" + "symbol": "лв", + "name": "Bulgarian Lev", + "ISO4217": "975" }, "BHD": { - "symbol": "BHD", - "name": "Bahraini Dinar", - "ISO4217": "048" + "symbol": "BHD", + "name": "Bahraini Dinar", + "ISO4217": "048" }, "BIF": { - "symbol": "FBu", - "name": "Burundi Franc", - "decimals": 0, - "ISO4217": "108" + "symbol": "FBu", + "name": "Burundi Franc", + "decimals": 0, + "ISO4217": "108" }, "BMD": { - "symbol": "BD$", - "name": "Bermuda Dollar", - "ISO4217": "060" + "symbol": "BD$", + "name": "Bermuda Dollar", + "ISO4217": "060" }, "BND": { - "symbol": "BN$", - "name": "Brunei Dollar", - "ISO4217": "096" + "symbol": "BN$", + "name": "Brunei Dollar", + "ISO4217": "096" }, "BOB": { - "symbol": "Bs", - "name": "Bolivian Boliviano", - "ISO4217": "068" + "symbol": "Bs", + "name": "Bolivian Boliviano", + "ISO4217": "068" }, "BRL": { - "symbol": "R$", - "name": "Brazilian Real", - "ISO4217": "986" + "symbol": "R$", + "name": "Brazilian Real", + "ISO4217": "986" }, "BSD": { - "symbol": "BS$", - "name": "Bahamian Dollar", - "ISO4217": "044" + "symbol": "BS$", + "name": "Bahamian Dollar", + "ISO4217": "044" }, "BTN": { - "symbol": "Nu.", - "name": "Bhutan Ngultrum", - "ISO4217": "064" + "symbol": "Nu.", + "name": "Bhutan Ngultrum", + "ISO4217": "064" }, "BWP": { - "symbol": "P", - "name": "Botswana Pula", - "ISO4217": "072" + "symbol": "P", + "name": "Botswana Pula", + "ISO4217": "072" }, "BYN": { - "symbol": "BR", - "name": "Belarus Ruble", - "ISO4217": "933" + "symbol": "BR", + "name": "Belarus Ruble", + "ISO4217": "933" }, "BYR": { - "symbol": "BR", - "name": "Belarus Ruble", - "decimals": 0, - "retired": true, - "retirementDate": "2016-07-01", - "ISO4217": "974" + "symbol": "BR", + "name": "Belarus Ruble", + "decimals": 0, + "retired": true, + "retirementDate": "2016-07-01", + "ISO4217": "974" }, "BZD": { - "symbol": "BZ$", - "name": "Belize Dollar", - "ISO4217": "084" + "symbol": "BZ$", + "name": "Belize Dollar", + "ISO4217": "084" }, "CAD": { - "symbol": "C$", - "name": "Canadian Dollar", - "ISO4217": "124" + "symbol": "C$", + "name": "Canadian Dollar", + "ISO4217": "124" }, "CDF": { - "symbol": "CDF", - "name": "Congolese Franc", - "ISO4217": "976" + "symbol": "CDF", + "name": "Congolese Franc", + "ISO4217": "976" }, "CHF": { - "symbol": "CHF", - "name": "Swiss Franc", - "ISO4217": "756" + "symbol": "CHF", + "name": "Swiss Franc", + "ISO4217": "756" }, "CLP": { - "symbol": "Ch$", - "name": "Chilean Peso", - "decimals": 0, - "ISO4217": "152" + "symbol": "Ch$", + "name": "Chilean Peso", + "decimals": 0, + "ISO4217": "152" }, "CNY": { - "symbol": "¥", - "name": "Chinese Yuan", - "ISO4217": "156" + "symbol": "¥", + "name": "Chinese Yuan", + "ISO4217": "156" }, "COP": { - "symbol": "Col$", - "name": "Colombian Peso", - "decimals": 0, - "ISO4217": "170" + "symbol": "Col$", + "name": "Colombian Peso", + "decimals": 0, + "ISO4217": "170" }, "CRC": { - "symbol": "CR₡", - "name": "Costa Rica Colon", - "ISO4217": "188" + "symbol": "CR₡", + "name": "Costa Rica Colon", + "ISO4217": "188" }, "CUC": { - "symbol": "CUC", - "name": "Cuban Convertible Peso", - "ISO4217": "931" + "symbol": "CUC", + "name": "Cuban Convertible Peso", + "ISO4217": "931" }, "CUP": { - "symbol": "$MN", - "name": "Cuban Peso", - "ISO4217": "192" + "symbol": "$MN", + "name": "Cuban Peso", + "ISO4217": "192" }, "CVE": { - "symbol": "Esc", - "name": "Cape Verde Escudo", - "ISO4217": "132" + "symbol": "Esc", + "name": "Cape Verde Escudo", + "ISO4217": "132" }, "CZK": { - "symbol": "Kč", - "name": "Czech Koruna", - "ISO4217": "203" + "symbol": "Kč", + "name": "Czech Koruna", + "ISO4217": "203" }, "DJF": { - "symbol": "Fdj", - "name": "Dijibouti Franc", - "decimals": 0, - "ISO4217": "262" + "symbol": "Fdj", + "name": "Dijibouti Franc", + "decimals": 0, + "ISO4217": "262" }, "DKK": { - "symbol": "Dkr", - "name": "Danish Krone", - "ISO4217": "208" + "symbol": "Dkr", + "name": "Danish Krone", + "ISO4217": "208" }, "DOP": { - "symbol": "RD$", - "name": "Dominican Peso", - "ISO4217": "214" + "symbol": "RD$", + "name": "Dominican Peso", + "ISO4217": "214" }, "DZD": { - "symbol": "DZD", - "name": "Algerian Dinar", - "ISO4217": "012" + "symbol": "DZD", + "name": "Algerian Dinar", + "ISO4217": "012" }, "EEK": { - "symbol": "KR", - "name": "Estonian Kroon", - "ISO4217": "", - "retired": true + "symbol": "KR", + "name": "Estonian Kroon", + "ISO4217": "", + "retired": true }, "EGP": { - "symbol": "EGP", - "name": "Egyptian Pound", - "ISO4217": "818" + "symbol": "EGP", + "name": "Egyptian Pound", + "ISO4217": "818" }, "ERN": { - "symbol": "Nfk", - "name": "Eritrea Nakfa", - "ISO4217": "232" + "symbol": "Nfk", + "name": "Eritrea Nakfa", + "ISO4217": "232" }, "ETB": { - "symbol": "Br", - "name": "Ethiopian Birr", - "ISO4217": "230" + "symbol": "Br", + "name": "Ethiopian Birr", + "ISO4217": "230" }, "EUR": { - "symbol": "€", - "name": "Euro", - "ISO4217": "978" + "symbol": "€", + "name": "Euro", + "ISO4217": "978" }, "FJD": { - "symbol": "FJ$", - "name": "Fiji Dollar", - "ISO4217": "242" + "symbol": "FJ$", + "name": "Fiji Dollar", + "ISO4217": "242" }, "FKP": { - "symbol": "FK£", - "name": "Falkland Islands Pound", - "ISO4217": "238" + "symbol": "FK£", + "name": "Falkland Islands Pound", + "ISO4217": "238" }, "GBP": { - "symbol": "£", - "name": "British Pound", - "ISO4217": "826" + "symbol": "£", + "name": "British Pound", + "ISO4217": "826" }, "GEL": { - "symbol": "ლ", - "name": "Georgian Lari", - "ISO4217": "981" + "symbol": "ლ", + "name": "Georgian Lari", + "ISO4217": "981" }, "GHS": { - "symbol": "₵", - "name": "Ghanaian Cedi", - "ISO4217": "936" + "symbol": "₵", + "name": "Ghanaian Cedi", + "ISO4217": "936" }, "GIP": { - "symbol": "£G", - "name": "Gibraltar Pound", - "ISO4217": "292" + "symbol": "£G", + "name": "Gibraltar Pound", + "ISO4217": "292" }, "GMD": { - "symbol": "D", - "name": "Gambian Dalasi", - "ISO4217": "270" + "symbol": "D", + "name": "Gambian Dalasi", + "ISO4217": "270" }, "GNF": { - "symbol": "FG", - "name": "Guinea Franc", - "decimals": 0, - "ISO4217": "324" + "symbol": "FG", + "name": "Guinea Franc", + "decimals": 0, + "ISO4217": "324" }, "GTQ": { - "symbol": "Q", - "name": "Guatemala Quetzal", - "ISO4217": "320" + "symbol": "Q", + "name": "Guatemala Quetzal", + "ISO4217": "320" }, "GYD": { - "symbol": "GY$", - "name": "Guyana Dollar", - "ISO4217": "328" + "symbol": "GY$", + "name": "Guyana Dollar", + "ISO4217": "328" }, "HKD": { - "symbol": "HK$", - "name": "Hong Kong Dollar", - "ISO4217": "344" + "symbol": "HK$", + "name": "Hong Kong Dollar", + "ISO4217": "344" }, "HNL": { - "symbol": "HNL", - "name": "Honduras Lempira", - "ISO4217": "340" + "symbol": "HNL", + "name": "Honduras Lempira", + "ISO4217": "340" }, "HRK": { - "symbol": "kn", - "name": "Croatian Kuna", - "ISO4217": "191" + "symbol": "kn", + "name": "Croatian Kuna", + "ISO4217": "191" }, "HTG": { - "symbol": "G", - "name": "Haiti Gourde", - "ISO4217": "332" + "symbol": "G", + "name": "Haiti Gourde", + "ISO4217": "332" }, "HUF": { - "symbol": "Ft", - "name": "Hungarian Forint", - "ISO4217": "348" + "symbol": "Ft", + "name": "Hungarian Forint", + "ISO4217": "348" }, "IDR": { - "symbol": "Rp", - "name": "Indonesian Rupiah", - "ISO4217": "360" + "symbol": "Rp", + "name": "Indonesian Rupiah", + "ISO4217": "360" }, "ILS": { - "symbol": "₪", - "name": "Israeli Shekel", - "ISO4217": "376" + "symbol": "₪", + "name": "Israeli Shekel", + "ISO4217": "376" }, "INR": { - "symbol": "₹", - "name": "Indian Rupee", - "ISO4217": "356" + "symbol": "₹", + "name": "Indian Rupee", + "ISO4217": "356" }, "IQD": { - "symbol": "IQD", - "name": "Iraqi Dinar", - "decimals": 0, - "ISO4217": "368" + "symbol": "IQD", + "name": "Iraqi Dinar", + "decimals": 0, + "ISO4217": "368" }, "IRR": { - "symbol": "﷼", - "name": "Iran Rial", - "decimals": 0, - "ISO4217": "364" + "symbol": "﷼", + "name": "Iran Rial", + "decimals": 0, + "ISO4217": "364" }, "ISK": { - "symbol": "kr", - "name": "Iceland Krona", - "decimals": 0, - "ISO4217": "352" + "symbol": "kr", + "name": "Iceland Krona", + "decimals": 0, + "ISO4217": "352" }, "JMD": { - "symbol": "J$", - "name": "Jamaican Dollar", - "ISO4217": "388" + "symbol": "J$", + "name": "Jamaican Dollar", + "ISO4217": "388" }, "JOD": { - "symbol": "JOD", - "name": "Jordanian Dinar", - "ISO4217": "400" + "symbol": "JOD", + "name": "Jordanian Dinar", + "ISO4217": "400" }, "JPY": { - "symbol": "¥", - "name": "Japanese Yen", - "decimals": 0, - "ISO4217": "392" + "symbol": "¥", + "name": "Japanese Yen", + "decimals": 0, + "ISO4217": "392" }, "KES": { - "symbol": "KSh", - "name": "Kenyan Shilling", - "ISO4217": "404" + "symbol": "KSh", + "name": "Kenyan Shilling", + "ISO4217": "404" }, "KGS": { - "symbol": "KGS", - "name": "Kyrgyzstani Som", - "ISO4217": "417" + "symbol": "KGS", + "name": "Kyrgyzstani Som", + "ISO4217": "417" }, "KHR": { - "symbol": "KHR", - "name": "Cambodia Riel", - "ISO4217": "116" + "symbol": "KHR", + "name": "Cambodia Riel", + "ISO4217": "116" }, "KMF": { - "symbol": "CF", - "name": "Comoros Franc", - "decimals": 0, - "ISO4217": "174" + "symbol": "CF", + "name": "Comoros Franc", + "decimals": 0, + "ISO4217": "174" }, "KPW": { - "symbol": "KP₩", - "name": "North Korean Won", - "decimals": 0, - "ISO4217": "408" + "symbol": "KP₩", + "name": "North Korean Won", + "decimals": 0, + "ISO4217": "408" }, "KRW": { - "symbol": "₩", - "name": "Korean Won", - "decimals": 0, - "ISO4217": "410" + "symbol": "₩", + "name": "Korean Won", + "decimals": 0, + "ISO4217": "410" }, "KWD": { - "symbol": "KWD", - "name": "Kuwaiti Dinar", - "ISO4217": "414" + "symbol": "KWD", + "name": "Kuwaiti Dinar", + "ISO4217": "414" }, "KYD": { - "symbol": "CI$", - "name": "Cayman Islands Dollar", - "ISO4217": "136" + "symbol": "CI$", + "name": "Cayman Islands Dollar", + "ISO4217": "136" }, "KZT": { - "symbol": "〒", - "name": "Kazakhstan Tenge", - "ISO4217": "398" + "symbol": "〒", + "name": "Kazakhstan Tenge", + "ISO4217": "398" }, "LAK": { - "symbol": "₭", - "name": "Lao Kip", - "decimals": 0, - "ISO4217": "418" + "symbol": "₭", + "name": "Lao Kip", + "decimals": 0, + "ISO4217": "418" }, "LBP": { - "symbol": "LBP", - "name": "Lebanese Pound", - "decimals": 0, - "ISO4217": "422" + "symbol": "LBP", + "name": "Lebanese Pound", + "decimals": 0, + "ISO4217": "422" }, "LKR": { - "symbol": "SL₨", - "name": "Sri Lanka Rupee", - "ISO4217": "144" + "symbol": "SL₨", + "name": "Sri Lanka Rupee", + "ISO4217": "144" }, "LRD": { - "symbol": "L$", - "name": "Liberian Dollar", - "ISO4217": "430" + "symbol": "L$", + "name": "Liberian Dollar", + "ISO4217": "430" }, "LSL": { - "symbol": "M", - "name": "Lesotho Loti", - "ISO4217": "426" + "symbol": "M", + "name": "Lesotho Loti", + "ISO4217": "426" }, "LTL": { - "symbol": "Lt", - "name": "Lithuanian Lita", - "retirementDate": "2015-08-22", - "retired": true, - "ISO4217": "440" + "symbol": "Lt", + "name": "Lithuanian Lita", + "retirementDate": "2015-08-22", + "retired": true, + "ISO4217": "440" }, "LVL": { - "symbol": "Ls", - "name": "Latvian Lat", - "ISO4217": "428", - "retired": true + "symbol": "Ls", + "name": "Latvian Lat", + "ISO4217": "428", + "retired": true }, "LYD": { - "symbol": "LYD", - "name": "Libyan Dinar", - "ISO4217": "434" + "symbol": "LYD", + "name": "Libyan Dinar", + "ISO4217": "434" }, "MAD": { - "symbol": "MAD", - "name": "Moroccan Dirham", - "ISO4217": "504" + "symbol": "MAD", + "name": "Moroccan Dirham", + "ISO4217": "504" }, "MDL": { - "symbol": "MDL", - "name": "Moldovan Leu", - "ISO4217": "498" + "symbol": "MDL", + "name": "Moldovan Leu", + "ISO4217": "498" }, "MGA": { - "symbol": "MGA", - "name": "Malagasy Ariary", - "decimals": 0, - "ISO4217": "969" + "symbol": "MGA", + "name": "Malagasy Ariary", + "decimals": 0, + "ISO4217": "969" }, "MKD": { - "symbol": "ден", - "name": "Macedonian Denar", - "ISO4217": "807" + "symbol": "ден", + "name": "Macedonian Denar", + "ISO4217": "807" }, "MMK": { - "symbol": "Ks", - "name": "Myanmar Kyat", - "decimals": 0, - "ISO4217": "104" + "symbol": "Ks", + "name": "Myanmar Kyat", + "decimals": 0, + "ISO4217": "104" }, "MNT": { - "symbol": "₮", - "name": "Mongolian Tugrik", - "ISO4217": "496" + "symbol": "₮", + "name": "Mongolian Tugrik", + "ISO4217": "496" }, "MOP": { - "symbol": "MOP$", - "name": "Macau Pataca", - "ISO4217": "446" + "symbol": "MOP$", + "name": "Macau Pataca", + "ISO4217": "446" }, "MRO": { - "symbol": "UM", - "name": "Mauritania Ougulya", - "decimals": 0, - "retired": true, - "retirementDate": "2018-07-11", - "ISO4217": "478" + "symbol": "UM", + "name": "Mauritania Ougulya", + "decimals": 0, + "retired": true, + "retirementDate": "2018-07-11", + "ISO4217": "478" }, "MRU": { - "symbol": "UM", - "name": "Mauritania Ougulya", - "decimals": 0, - "ISO4217": "" + "symbol": "UM", + "name": "Mauritania Ougulya", + "decimals": 0, + "ISO4217": "" }, "MUR": { - "symbol": "Rs", - "name": "Mauritius Rupee", - "ISO4217": "480" + "symbol": "Rs", + "name": "Mauritius Rupee", + "ISO4217": "480" }, "MVR": { - "symbol": "Rf", - "name": "Maldives Rufiyaa", - "ISO4217": "462" + "symbol": "Rf", + "name": "Maldives Rufiyaa", + "ISO4217": "462" }, "MWK": { - "symbol": "MK", - "name": "Malawi Kwacha", - "ISO4217": "454" + "symbol": "MK", + "name": "Malawi Kwacha", + "ISO4217": "454" }, "MXN": { - "symbol": "Mex$", - "name": "Mexican Peso", - "ISO4217": "484" + "symbol": "Mex$", + "name": "Mexican Peso", + "ISO4217": "484" }, "MYR": { - "symbol": "RM", - "name": "Malaysian Ringgit", - "ISO4217": "458" + "symbol": "RM", + "name": "Malaysian Ringgit", + "ISO4217": "458" }, "MZN": { - "symbol": "MTn", - "name": "Mozambican Metical", - "ISO4217": "943" + "symbol": "MTn", + "name": "Mozambican Metical", + "ISO4217": "943" }, "NAD": { - "symbol": "N$", - "name": "Namibian Dollar", - "ISO4217": "516" + "symbol": "N$", + "name": "Namibian Dollar", + "ISO4217": "516" }, "NGN": { - "symbol": "₦", - "name": "Nigerian Naira", - "ISO4217": "566" + "symbol": "₦", + "name": "Nigerian Naira", + "ISO4217": "566" }, "NIO": { - "symbol": "NIO", - "name": "Nicaragua Cordoba", - "ISO4217": "558" + "symbol": "NIO", + "name": "Nicaragua Cordoba", + "ISO4217": "558" }, "NOK": { - "symbol": "Nkr", - "name": "Norwegian Krone", - "ISO4217": "578" + "symbol": "Nkr", + "name": "Norwegian Krone", + "ISO4217": "578" }, "NPR": { - "symbol": "₨", - "name": "Nepalese Rupee", - "ISO4217": "524" + "symbol": "₨", + "name": "Nepalese Rupee", + "ISO4217": "524" }, "NZD": { - "symbol": "NZ$", - "name": "New Zealand Dollar", - "ISO4217": "554" + "symbol": "NZ$", + "name": "New Zealand Dollar", + "ISO4217": "554" }, "OMR": { - "symbol": "OMR", - "name": "Omani Rial", - "ISO4217": "512" + "symbol": "OMR", + "name": "Omani Rial", + "ISO4217": "512" }, "PAB": { - "symbol": "B", - "name": "Panama Balboa", - "ISO4217": "590" + "symbol": "B", + "name": "Panama Balboa", + "ISO4217": "590" }, "PEN": { - "symbol": "S/.", - "name": "Peruvian Nuevo Sol", - "ISO4217": "604" + "symbol": "S/.", + "name": "Peruvian Nuevo Sol", + "ISO4217": "604" }, "PGK": { - "symbol": "K", - "name": "Papua New Guinea Kina", - "ISO4217": "598" + "symbol": "K", + "name": "Papua New Guinea Kina", + "ISO4217": "598" }, "PHP": { - "symbol": "₱", - "name": "Philippine Peso", - "ISO4217": "608" + "symbol": "₱", + "name": "Philippine Peso", + "ISO4217": "608" }, "PKR": { - "symbol": "Rs", - "name": "Pakistani Rupee", - "ISO4217": "586" + "symbol": "Rs", + "name": "Pakistani Rupee", + "ISO4217": "586" }, "PLN": { - "symbol": "zł", - "name": "Polish Zloty", - "ISO4217": "985" + "symbol": "zł", + "name": "Polish Zloty", + "ISO4217": "985" }, "PYG": { - "symbol": "₲", - "name": "Paraguayan Guarani", - "decimals": 0, - "ISO4217": "600" + "symbol": "₲", + "name": "Paraguayan Guarani", + "decimals": 0, + "ISO4217": "600" }, "QAR": { - "symbol": "QAR", - "name": "Qatar Rial", - "ISO4217": "634" + "symbol": "QAR", + "name": "Qatar Rial", + "ISO4217": "634" }, "RON": { - "symbol": "RON", - "name": "Romanian New Leu", - "ISO4217": "946" + "symbol": "RON", + "name": "Romanian New Leu", + "ISO4217": "946" }, "RSD": { - "symbol": "РСД", - "name": "Serbian Dinar", - "decimals": 0, - "ISO4217": "941" + "symbol": "РСД", + "name": "Serbian Dinar", + "decimals": 0, + "ISO4217": "941" }, "RUB": { - "symbol": "₽", - "name": "Russian Rouble", - "ISO4217": "643" + "symbol": "₽", + "name": "Russian Rouble", + "ISO4217": "643" }, "RWF": { - "symbol": "RF", - "name": "Rwanda Franc", - "decimals": 0, - "ISO4217": "646" + "symbol": "RF", + "name": "Rwanda Franc", + "decimals": 0, + "ISO4217": "646" }, "SAR": { - "symbol": "SAR", - "name": "Saudi Arabian Riyal", - "ISO4217": "682" + "symbol": "SAR", + "name": "Saudi Arabian Riyal", + "ISO4217": "682" }, "SBD": { - "symbol": "SI$", - "name": "Solomon Islands Dollar", - "ISO4217": "090" + "symbol": "SI$", + "name": "Solomon Islands Dollar", + "ISO4217": "090" }, "SCR": { - "symbol": "SR", - "name": "Seychelles Rupee", - "ISO4217": "690" + "symbol": "SR", + "name": "Seychelles Rupee", + "ISO4217": "690" }, "SDG": { - "symbol": "SDG", - "name": "Sudanese Pound", - "ISO4217": "938" + "symbol": "SDG", + "name": "Sudanese Pound", + "ISO4217": "938" }, "SEK": { - "symbol": "Skr", - "name": "Swedish Krona", - "ISO4217": "752" + "symbol": "Skr", + "name": "Swedish Krona", + "ISO4217": "752" }, "SGD": { - "symbol": "S$", - "name": "Singapore Dollar", - "ISO4217": "702" + "symbol": "S$", + "name": "Singapore Dollar", + "ISO4217": "702" }, "SHP": { - "symbol": "£S", - "name": "St Helena Pound", - "ISO4217": "654" + "symbol": "£S", + "name": "St Helena Pound", + "ISO4217": "654" }, "SLL": { - "symbol": "Le", - "name": "Sierra Leone Leone", - "decimals": 0, - "ISO4217": "694" + "symbol": "Le", + "name": "Sierra Leone Leone", + "decimals": 0, + "ISO4217": "694" }, "SOS": { - "symbol": "So.", - "name": "Somali Shilling", - "decimals": 0, - "ISO4217": "706" + "symbol": "So.", + "name": "Somali Shilling", + "decimals": 0, + "ISO4217": "706" }, "SRD": { - "symbol": "SRD", - "name": "Surinamese Dollar", - "ISO4217": "968" + "symbol": "SRD", + "name": "Surinamese Dollar", + "ISO4217": "968" }, "STD": { - "symbol": "Db", - "name": "Sao Tome Dobra", - "decimals": 0, - "retired": true, - "retirementDate": "2018-07-11", - "ISO4217": "678" + "symbol": "Db", + "name": "Sao Tome Dobra", + "decimals": 0, + "retired": true, + "retirementDate": "2018-07-11", + "ISO4217": "678" }, "STN": { - "symbol": "Db", - "name": "Sao Tome Dobra", - "ISO4217": "" + "symbol": "Db", + "name": "Sao Tome Dobra", + "ISO4217": "" }, "SVC": { - "symbol": "SVC", - "name": "El Salvador Colon", - "ISO4217": "222" + "symbol": "SVC", + "name": "El Salvador Colon", + "ISO4217": "222" }, "SYP": { - "symbol": "SYP", - "name": "Syrian Pound", - "decimals": 0, - "ISO4217": "760" + "symbol": "SYP", + "name": "Syrian Pound", + "decimals": 0, + "ISO4217": "760" }, "SZL": { - "symbol": "E", - "name": "Swaziland Lilageni", - "ISO4217": "748" + "symbol": "E", + "name": "Swaziland Lilageni", + "ISO4217": "748" }, "THB": { - "symbol": "฿", - "name": "Thai Baht", - "ISO4217": "764" + "symbol": "฿", + "name": "Thai Baht", + "ISO4217": "764" }, "TJS": { - "symbol": "TJS", - "name": "Tajikistani Somoni", - "ISO4217": "972" + "symbol": "TJS", + "name": "Tajikistani Somoni", + "ISO4217": "972" }, "TMT": { - "symbol": "m", - "name": "Turkmenistani Manat", - "ISO4217": "934" + "symbol": "m", + "name": "Turkmenistani Manat", + "ISO4217": "934" }, "TND": { - "symbol": "TND", - "name": "Tunisian Dinar", - "ISO4217": "788" + "symbol": "TND", + "name": "Tunisian Dinar", + "ISO4217": "788" }, "TOP": { - "symbol": "T$", - "name": "Tonga Pa'ang", - "ISO4217": "776" + "symbol": "T$", + "name": "Tonga Pa'ang", + "ISO4217": "776" }, "TRY": { - "symbol": "TL", - "name": "Turkish Lira", - "ISO4217": "949" + "symbol": "TL", + "name": "Turkish Lira", + "ISO4217": "949" }, "TTD": { - "symbol": "TT$", - "name": "Trinidad & Tobago Dollar", - "ISO4217": "780" + "symbol": "TT$", + "name": "Trinidad & Tobago Dollar", + "ISO4217": "780" }, "TWD": { - "symbol": "NT$", - "name": "Taiwan Dollar", - "ISO4217": "901" + "symbol": "NT$", + "name": "Taiwan Dollar", + "ISO4217": "901" }, "TZS": { - "symbol": "TZS", - "name": "Tanzanian Shilling", - "ISO4217": "834" + "symbol": "TZS", + "name": "Tanzanian Shilling", + "ISO4217": "834" }, "UAH": { - "symbol": "₴", - "name": "Ukraine Hryvnia", - "ISO4217": "980" + "symbol": "₴", + "name": "Ukraine Hryvnia", + "ISO4217": "980" }, "UGX": { - "symbol": "USh", - "name": "Ugandan Shilling", - "decimals": 0, - "ISO4217": "800" + "symbol": "USh", + "name": "Ugandan Shilling", + "decimals": 0, + "ISO4217": "800" }, "USD": { - "symbol": "$", - "name": "United States Dollar", - "ISO4217": "840" + "symbol": "$", + "name": "United States Dollar", + "ISO4217": "840" }, "UYU": { - "symbol": "$U", - "name": "Uruguayan New Peso", - "ISO4217": "858" + "symbol": "$U", + "name": "Uruguayan New Peso", + "ISO4217": "858" }, "UZS": { - "symbol": "UZS", - "name": "Uzbekistani Som", - "ISO4217": "860" + "symbol": "UZS", + "name": "Uzbekistani Som", + "ISO4217": "860" }, "VEB": { - "symbol": "Bs.", - "name": "Venezuelan Bolivar", - "retired": true, - "retirementDate": "2008-02-01", - "ISO4217": "" + "symbol": "Bs.", + "name": "Venezuelan Bolivar", + "retired": true, + "retirementDate": "2008-02-01", + "ISO4217": "" }, "VEF": { - "symbol": "Bs.F", - "name": "Venezuelan Bolivar Fuerte", - "retired": true, - "retirementDate": "2018-08-20", - "ISO4217": "937" + "symbol": "Bs.F", + "name": "Venezuelan Bolivar Fuerte", + "retired": true, + "retirementDate": "2018-08-20", + "ISO4217": "937" }, "VES": { - "symbol": "Bs.S", - "name": "Venezuelan Bolivar Soberano", - "ISO4217": "928" + "symbol": "Bs.S", + "name": "Venezuelan Bolivar Soberano", + "ISO4217": "928" }, "VND": { - "symbol": "₫", - "name": "Vietnam Dong", - "decimals": 0, - "ISO4217": "704" + "symbol": "₫", + "name": "Vietnam Dong", + "decimals": 0, + "ISO4217": "704" }, "VUV": { - "symbol": "Vt", - "name": "Vanuatu Vatu", - "decimals": 0, - "ISO4217": "548" + "symbol": "Vt", + "name": "Vanuatu Vatu", + "decimals": 0, + "ISO4217": "548" }, "WST": { - "symbol": "WS$", - "name": "Samoa Tala", - "ISO4217": "882" + "symbol": "WS$", + "name": "Samoa Tala", + "ISO4217": "882" }, "XAF": { - "symbol": "FCFA", - "name": "CFA Franc (BEAC)", - "decimals": 0, - "ISO4217": "950" + "symbol": "FCFA", + "name": "CFA Franc (BEAC)", + "decimals": 0, + "ISO4217": "950" }, "XCD": { - "symbol": "EC$", - "name": "East Caribbean Dollar", - "ISO4217": "951" + "symbol": "EC$", + "name": "East Caribbean Dollar", + "ISO4217": "951" }, "XOF": { - "symbol": "CFA", - "name": "CFA Franc (BCEAO)", - "decimals": 0, - "ISO4217": "952" + "symbol": "CFA", + "name": "CFA Franc (BCEAO)", + "decimals": 0, + "ISO4217": "952" }, "XPF": { - "symbol": "XPF", - "name": "Pacific Franc", - "decimals": 0, - "ISO4217": "953" + "symbol": "XPF", + "name": "Pacific Franc", + "decimals": 0, + "ISO4217": "953" }, "YER": { - "symbol": "YER", - "name": "Yemen Riyal", - "decimals": 0, - "ISO4217": "886" + "symbol": "YER", + "name": "Yemen Riyal", + "decimals": 0, + "ISO4217": "886" }, "ZAR": { - "symbol": "R", - "name": "South African Rand", - "ISO4217": "710" + "symbol": "R", + "name": "South African Rand", + "ISO4217": "710" }, "ZMK": { - "symbol": "ZK", - "name": "Zambian Kwacha", - "decimals": 0, - "retired": true, - "retirementDate": "2013-01-01", - "ISO4217": "894" + "symbol": "ZK", + "name": "Zambian Kwacha", + "decimals": 0, + "retired": true, + "retirementDate": "2013-01-01", + "ISO4217": "894" }, "ZMW": { - "symbol": "ZMW", - "name": "Zambian Kwacha", - "cacheBurst": 1, - "ISO4217": "967" + "symbol": "ZMW", + "name": "Zambian Kwacha", + "cacheBurst": 1, + "ISO4217": "967" } } From 39d7ca24fd8c28f0a9fa5ef998703873432f0d7f Mon Sep 17 00:00:00 2001 From: Sujit Kumar <60378235+therealsujitk@users.noreply.github.com> Date: Fri, 26 May 2023 17:56:03 +0530 Subject: [PATCH 361/751] Deprecate setShouldBlockSuggestionsCalcToFalse --- src/pages/home/report/ReportActionCompose.js | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index a5cc77136d4f..72b0cd27da25 100644 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -183,7 +183,6 @@ class ReportActionCompose extends React.Component { this.updateNumberOfLines = this.updateNumberOfLines.bind(this); this.showPopoverMenu = this.showPopoverMenu.bind(this); this.comment = props.comment; - this.setShouldBlockSuggestionsCalcToFalse = this.setShouldBlockSuggestionsCalcToFalse.bind(this); // React Native will retain focus on an input for native devices but web/mWeb behave differently so we have some focus management // code that will refocus the compose input after a user closes a modal or some other actions, see usage of ReportActionComposeFocusManager @@ -290,13 +289,13 @@ class ReportActionCompose extends React.Component { this.setState({selection: e.nativeEvent.selection}); if (!this.state.value || e.nativeEvent.selection.end < 1) { this.resetSuggestions(); - this.setShouldBlockSuggestionsCalcToFalse(); + this.shouldBlockSuggestionsCalc = false; return; } } if (this.shouldBlockSuggestionsCalc) { - this.setShouldBlockSuggestionsCalcToFalse(); + this.shouldBlockSuggestionsCalc = false; return; } @@ -436,11 +435,6 @@ class ReportActionCompose extends React.Component { } } - // eslint-disable-next-line rulesdir/prefer-early-return - setShouldBlockSuggestionsCalcToFalse() { - this.shouldBlockSuggestionsCalc = false; - } - /** * Determines if we can show the task option * @param {Array} reportParticipants @@ -951,7 +945,7 @@ class ReportActionCompose extends React.Component { onConfirm={this.addAttachment} onModalShow={() => this.setState({isAttachmentPreviewActive: true})} onModalHide={() => { - this.setShouldBlockSuggestionsCalcToFalse(); + this.shouldBlockSuggestionsCalc = false; this.setState({isAttachmentPreviewActive: false}); }} > @@ -1090,7 +1084,7 @@ class ReportActionCompose extends React.Component { this.resetSuggestions(); }} onClick={() => { - this.setShouldBlockSuggestionsCalcToFalse(); + this.shouldBlockSuggestionsCalc = false; this.onSelectionChange(); }} onPasteFile={displayFileInModal} From a05f04ce0c6a862371111ced318b43132b8ff32c Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Fri, 26 May 2023 20:35:55 +0800 Subject: [PATCH 362/751] update variable name --- src/styles/getTooltipStyles.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/styles/getTooltipStyles.js b/src/styles/getTooltipStyles.js index 1d77ce1cddc5..9ce065e734c5 100644 --- a/src/styles/getTooltipStyles.js +++ b/src/styles/getTooltipStyles.js @@ -57,15 +57,15 @@ function computeHorizontalShift(windowWidth, xOffset, componentWidth, tooltipWid * @param {Number} yOffset - The distance between the top edge of the window * and the top edge of the wrapped component. * @param {Element} [tooltip] - The reference to the tooltip's root element - * @param {Number} componentHeight - The height of the wrapped component. + * @param {Number} tooltipTargetHeight - The height of the tooltip's target * @returns {Boolean} */ -function isOverlappingAtTop(xOffset, yOffset, tooltip, componentHeight) { +function isOverlappingAtTop(xOffset, yOffset, tooltip, tooltipTargetHeight) { if (typeof document.elementFromPoint !== 'function') { return false; } - const centerY = yOffset + componentHeight / 2; + const centerY = yOffset + tooltipTargetHeight / 2; const element = document.elementFromPoint(xOffset, centerY); const tooltipRef = (tooltip && tooltip.current) || tooltip; From c5715ca379a12e84102e90675931acc741055ab7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czernek?= Date: Fri, 26 May 2023 14:42:10 +0200 Subject: [PATCH 363/751] Add empty line as per guidelines. --- .prettierignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.prettierignore b/.prettierignore index 01419fde288c..5f6292b551c1 100644 --- a/.prettierignore +++ b/.prettierignore @@ -14,4 +14,4 @@ package-lock.json *.yaml *.css *.scss -*.md \ No newline at end of file +*.md From 177d42aea1b10cb3c21832eb167d102ad54ad68b Mon Sep 17 00:00:00 2001 From: OSBotify Date: Fri, 26 May 2023 12:53:42 +0000 Subject: [PATCH 364/751] Update version to 1.3.19-2 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NewExpensifyTests/Info.plist | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index fb390da75cc1..dfe56dc042a6 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -106,8 +106,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001031901 - versionName "1.3.19-1" + versionCode 1001031902 + versionName "1.3.19-2" } splits { diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 56471e6e70d0..5e34573263b9 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -30,7 +30,7 @@ CFBundleVersion - 1.3.19.1 + 1.3.19.2 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 4fa6f0550dc7..c8053fbee84e 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.3.19.1 + 1.3.19.2 diff --git a/package-lock.json b/package-lock.json index d448db9913b5..aefc56e0f63c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.3.19-1", + "version": "1.3.19-2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.3.19-1", + "version": "1.3.19-2", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 8bbf35dbe003..63868a221b6e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.3.19-1", + "version": "1.3.19-2", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From fa8eb77dc26e091b30c8bc2bbc0c13812d327000 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Fri, 26 May 2023 16:04:47 +0300 Subject: [PATCH 365/751] Improve how we pass the twoFactorAuthCode to the server. --- .../ValidateCode/ValidateCodeModal.js | 2 +- src/libs/actions/Session/index.js | 29 +++++++++---------- src/pages/ValidateLoginPage/index.js | 2 +- src/pages/ValidateLoginPage/index.website.js | 2 +- .../ValidateCodeForm/BaseValidateCodeForm.js | 2 +- 5 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/components/ValidateCode/ValidateCodeModal.js b/src/components/ValidateCode/ValidateCodeModal.js index c356458dc877..344c3107b8cf 100644 --- a/src/components/ValidateCode/ValidateCodeModal.js +++ b/src/components/ValidateCode/ValidateCodeModal.js @@ -39,7 +39,7 @@ const defaultProps = { }; function ValidateCodeModal(props) { - const signInHere = useCallback(() => Session.signInWithValidateCode(props.accountID, props.code, null, props.preferredLocale), [props.accountID, props.code, props.preferredLocale]); + const signInHere = useCallback(() => Session.signInWithValidateCode(props.accountID, props.code, props.preferredLocale), [props.accountID, props.code, props.preferredLocale]); return ( diff --git a/src/libs/actions/Session/index.js b/src/libs/actions/Session/index.js index 6143c39090a7..cc832d63ff53 100644 --- a/src/libs/actions/Session/index.js +++ b/src/libs/actions/Session/index.js @@ -393,7 +393,7 @@ function signIn(password, validateCode, twoFactorAuthCode, preferredLocale = CON API.write('SigninUser', params, {optimisticData, successData, failureData}); } -function signInWithValidateCode(accountID, code, twoFactorAuthCode, preferredLocale = CONST.LOCALES.DEFAULT) { +function signInWithValidateCode(accountID, code, preferredLocale = CONST.LOCALES.DEFAULT, twoFactorAuthCode = '') { // If this is called from the 2fa step, get the validateCode directly from onyx // instead of the one passed from the component state because the state is changing when this method is called. const validateCode = twoFactorAuthCode ? credentials.validateCode : code; @@ -455,22 +455,21 @@ function signInWithValidateCode(accountID, code, twoFactorAuthCode, preferredLoc }, ]; - const params = { - accountID, - validateCode, - preferredLocale, - deviceInfo: getDeviceInfoForLogin(), - }; - - // Pass twoFactorAuthCode to server only if it has a valid value, otherwise php might convert it to "null" as a string. - if (twoFactorAuthCode) { - params.twoFactorAuthCode = twoFactorAuthCode; - } - API.write('SigninUserWithLink', params, {optimisticData, successData, failureData}); + API.write( + 'SigninUserWithLink', + { + accountID, + validateCode, + twoFactorAuthCode, + preferredLocale, + deviceInfo: getDeviceInfoForLogin(), + }, + {optimisticData, successData, failureData}, + ); } -function signInWithValidateCodeAndNavigate(accountID, validateCode, twoFactorAuthCode, preferredLocale = CONST.LOCALES.DEFAULT) { - signInWithValidateCode(accountID, validateCode, twoFactorAuthCode, preferredLocale); +function signInWithValidateCodeAndNavigate(accountID, validateCode, preferredLocale = CONST.LOCALES.DEFAULT, twoFactorAuthCode = '') { + signInWithValidateCode(accountID, validateCode, preferredLocale, twoFactorAuthCode); Navigation.navigate(ROUTES.HOME); } diff --git a/src/pages/ValidateLoginPage/index.js b/src/pages/ValidateLoginPage/index.js index 2f6e9c07e6e4..97461b42ab92 100644 --- a/src/pages/ValidateLoginPage/index.js +++ b/src/pages/ValidateLoginPage/index.js @@ -49,7 +49,7 @@ class ValidateLoginPage extends Component { // because we don't want to block the user with the interstitial page. Navigation.goBack(false); } else { - Session.signInWithValidateCodeAndNavigate(accountID, validateCode, null, this.props.preferredLocale); + Session.signInWithValidateCodeAndNavigate(accountID, validateCode, this.props.preferredLocale); } } else { User.validateLogin(accountID, validateCode); diff --git a/src/pages/ValidateLoginPage/index.website.js b/src/pages/ValidateLoginPage/index.website.js index 4f048dc30659..24a736086357 100644 --- a/src/pages/ValidateLoginPage/index.website.js +++ b/src/pages/ValidateLoginPage/index.website.js @@ -83,7 +83,7 @@ class ValidateLoginPage extends Component { } // The user has initiated the sign in process on the same browser, in another tab. - Session.signInWithValidateCode(this.getAccountID(), this.getValidateCode(), null, this.props.preferredLocale); + Session.signInWithValidateCode(this.getAccountID(), this.getValidateCode(), this.props.preferredLocale); } componentDidUpdate() { diff --git a/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js b/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js index c1e1dc0bc9ff..c250a15d7f4c 100755 --- a/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js +++ b/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js @@ -184,7 +184,7 @@ class BaseValidateCodeForm extends React.Component { const accountID = lodashGet(this.props, 'credentials.accountID'); if (accountID) { - Session.signInWithValidateCode(accountID, this.state.validateCode, this.state.twoFactorAuthCode, this.props.preferredLocale); + Session.signInWithValidateCode(accountID, this.state.validateCode, this.props.preferredLocale, this.state.twoFactorAuthCode); } else { Session.signIn('', this.state.validateCode, this.state.twoFactorAuthCode, this.props.preferredLocale); } From de55100c574f0b435631a2e33426085d79d7aa1c Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Fri, 26 May 2023 21:04:57 +0800 Subject: [PATCH 366/751] add comment --- src/styles/getTooltipStyles.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/styles/getTooltipStyles.js b/src/styles/getTooltipStyles.js index 9ce065e734c5..6d2e667016df 100644 --- a/src/styles/getTooltipStyles.js +++ b/src/styles/getTooltipStyles.js @@ -65,6 +65,7 @@ function isOverlappingAtTop(xOffset, yOffset, tooltip, tooltipTargetHeight) { return false; } + // Use the vertical center of the target to prevent wrong element returned by elementFromPoint in case the target has a border radius. const centerY = yOffset + tooltipTargetHeight / 2; const element = document.elementFromPoint(xOffset, centerY); const tooltipRef = (tooltip && tooltip.current) || tooltip; From 6a826efdcbb01446a842d0d086f87b6d46c3b2f6 Mon Sep 17 00:00:00 2001 From: VH Date: Fri, 26 May 2023 20:44:34 +0700 Subject: [PATCH 367/751] Fix resolve conflict mistake --- src/pages/home/report/ReactionList/BaseReactionList.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/ReactionList/BaseReactionList.js b/src/pages/home/report/ReactionList/BaseReactionList.js index d869d53917de..eda4f4db0f48 100755 --- a/src/pages/home/report/ReactionList/BaseReactionList.js +++ b/src/pages/home/report/ReactionList/BaseReactionList.js @@ -122,4 +122,4 @@ BaseReactionList.propTypes = propTypes; BaseReactionList.defaultProps = defaultProps; BaseReactionList.displayName = 'BaseReactionList'; -export default withWindowDimensions(BaseReactionList); \ No newline at end of file +export default withWindowDimensions(BaseReactionList); From 44556a03acccc6f3fa2386130a7739eb3232a711 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Ska=C5=82ka?= Date: Fri, 26 May 2023 15:47:58 +0200 Subject: [PATCH 368/751] migrate CurrencySymbolButton to PressableWithoutFeedback --- src/components/CurrencySymbolButton.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/components/CurrencySymbolButton.js b/src/components/CurrencySymbolButton.js index 8b73cabc1b23..b5929271031d 100644 --- a/src/components/CurrencySymbolButton.js +++ b/src/components/CurrencySymbolButton.js @@ -1,10 +1,10 @@ import React from 'react'; -import {TouchableOpacity} from 'react-native'; import PropTypes from 'prop-types'; import Text from './Text'; import styles from '../styles/styles'; import Tooltip from './Tooltip'; import withLocalize, {withLocalizePropTypes} from './withLocalize'; +import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback'; const propTypes = { /** Currency symbol of selected currency */ @@ -19,9 +19,13 @@ const propTypes = { function CurrencySymbolButton(props) { return ( - + {props.currencySymbol} - + ); } From 827f740a5ba5cc668f5be609b64f1eae562ad2e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Ch=C3=A1vez?= Date: Fri, 26 May 2023 07:52:28 -0600 Subject: [PATCH 369/751] don't retry openReport from deep link and add backwards compatibility --- src/libs/actions/Report.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index a8c08ac93a36..1d00a38fdd3b 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -323,8 +323,9 @@ function addComment(reportID, text) { * @param {Array} participantList The list of users that are included in a new chat, not including the user creating it * @param {Object} newReportObject The optimistic report object created when making a new chat, saved as optimistic data * @param {String} parentReportActionID The parent report action that a thread was created from (only passed for new threads) + * @param {Boolean} isFromDeepLink Whether or not this report is being opened from a deep link */ -function openReport(reportID, participantList = [], newReportObject = {}, parentReportActionID = '0') { +function openReport(reportID, participantList = [], newReportObject = {}, parentReportActionID = '0', isFromDeepLink = false) { const optimisticReportData = { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, @@ -369,6 +370,10 @@ function openReport(reportID, participantList = [], newReportObject = {}, parent parentReportActionID, }; + if (isFromDeepLink) { + params.shouldRetry = false; + } + // If we are creating a new report, we need to add the optimistic report data and a report action if (!_.isEmpty(newReportObject)) { // Change the method to set for new reports because it doesn't exist yet, is faster, @@ -416,7 +421,13 @@ function openReport(reportID, participantList = [], newReportObject = {}, parent } } - API.write('OpenReport', params, onyxData); + if (isFromDeepLink) { + API.makeRequestWithSideEffects('OpenReport', params, onyxData).finally(() => { + Onyx.set(ONYXKEYS.IS_CHECKING_PUBLIC_ROOM, false); + }); + } else { + API.write('OpenReport', params, onyxData); + } } /** @@ -1633,7 +1644,7 @@ function openReportFromDeepLink(url, isAuthenticated, isOffline) { if (reportID && !isAuthenticated) { // Check if it's a public room to open it as an anonymous user - openReport(reportID); + openReport(reportID, [], {}, '0', true); // Show the sign-in page if the app is offline if (isOffline) { From 08a527d11b0b013ed0ac7245d9018824519f3053 Mon Sep 17 00:00:00 2001 From: Konrad Bochnia Date: Fri, 26 May 2023 16:57:51 +0200 Subject: [PATCH 370/751] Migrate ExceededCommentLength to functional component --- src/components/ExceededCommentLength.js | 64 ++++++++++--------------- 1 file changed, 24 insertions(+), 40 deletions(-) diff --git a/src/components/ExceededCommentLength.js b/src/components/ExceededCommentLength.js index 4ef6a5027e73..9c39ae760a2a 100644 --- a/src/components/ExceededCommentLength.js +++ b/src/components/ExceededCommentLength.js @@ -1,4 +1,4 @@ -import React, {PureComponent} from 'react'; +import React, {useEffect, useState, useMemo} from 'react'; import PropTypes from 'prop-types'; import {debounce} from 'lodash'; import CONST from '../CONST'; @@ -14,47 +14,31 @@ const propTypes = { onExceededMaxCommentLength: PropTypes.func.isRequired, }; -class ExceededCommentLength extends PureComponent { - constructor(props) { - super(props); - - this.state = { - commentLength: 0, - }; - - // By debouncing, we defer the calculation until there is a break in typing - this.updateCommentLength = debounce(this.updateCommentLength.bind(this), CONST.TIMING.COMMENT_LENGTH_DEBOUNCE_TIME); - } - - componentDidMount() { - this.updateCommentLength(); +function ExceededCommentLength(props) { + const [commentLength, setCommentLength] = useState(0); + const updateCommentLength = useMemo( + () => + debounce((comment, onExceededMaxCommentLength) => { + const commentLength = ReportUtils.getCommentLength(comment); + setCommentLength(commentLength); + onExceededMaxCommentLength(commentLength > CONST.MAX_COMMENT_LENGTH); + }, CONST.TIMING.COMMENT_LENGTH_DEBOUNCE_TIME), + [], + ); + + useEffect(() => { + updateCommentLength(props.comment, props.onExceededMaxCommentLength); + }, [props.comment, props.onExceededMaxCommentLength]) + + if (commentLength <= CONST.MAX_COMMENT_LENGTH) { + return null; } - componentDidUpdate(prevProps) { - if (prevProps.comment === this.props.comment) { - return; - } - - this.updateCommentLength(); - } - - updateCommentLength() { - const commentLength = ReportUtils.getCommentLength(this.props.comment); - this.setState({commentLength}); - this.props.onExceededMaxCommentLength(commentLength > CONST.MAX_COMMENT_LENGTH); - } - - render() { - if (this.state.commentLength <= CONST.MAX_COMMENT_LENGTH) { - return null; - } - - return ( - - {`${this.state.commentLength}/${CONST.MAX_COMMENT_LENGTH}`} - - ); - } + return ( + + {`${commentLength}/${CONST.MAX_COMMENT_LENGTH}`} + + ); } ExceededCommentLength.propTypes = propTypes; From 5f0c1ad870777fc662ecfdc0c5e0e5b775ff4765 Mon Sep 17 00:00:00 2001 From: Sujit Kumar <60378235+therealsujitk@users.noreply.github.com> Date: Fri, 26 May 2023 20:32:22 +0530 Subject: [PATCH 371/751] Fix suggestions list issues with mWeb and revert changes --- src/pages/home/report/ReportActionCompose.js | 45 +++++++++++--------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index 72b0cd27da25..55ea4f485706 100644 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -194,8 +194,9 @@ class ReportActionCompose extends React.Component { this.shouldAutoFocus = !props.modal.isVisible && (this.shouldFocusInputOnScreenFocus || this.isEmptyChat()) && props.shouldShowComposeInput; - // This variable is used to decide whether to block the suggestions list from showing to prevent flickering - this.shouldBlockSuggestionsCalc = false; + // These variables are used to decide whether to block the suggestions list from showing to prevent flickering + this.shouldBlockEmojiCalc = false; + this.shouldBlockMentionCalc = false; // For mobile Safari, updating the selection prop on an unfocused input will cause it to automatically gain focus // and subsequent programmatic focus shifts (e.g., modal focus trap) to show the blue frame (:focus-visible style), @@ -284,21 +285,13 @@ class ReportActionCompose extends React.Component { onSelectionChange(e) { LayoutAnimation.configureNext(LayoutAnimation.create(50, LayoutAnimation.Types.easeInEaseOut, LayoutAnimation.Properties.opacity)); - - if (e) { - this.setState({selection: e.nativeEvent.selection}); - if (!this.state.value || e.nativeEvent.selection.end < 1) { - this.resetSuggestions(); - this.shouldBlockSuggestionsCalc = false; - return; - } - } - - if (this.shouldBlockSuggestionsCalc) { - this.shouldBlockSuggestionsCalc = false; + this.setState({selection: e.nativeEvent.selection}); + if (!this.state.value || e.nativeEvent.selection.end < 1) { + this.resetSuggestions(); + this.shouldBlockEmojiCalc = false; + this.shouldBlockMentionCalc = false; return; } - this.calculateEmojiSuggestion(); this.calculateMentionSuggestion(); } @@ -518,6 +511,11 @@ class ReportActionCompose extends React.Component { * Calculates and cares about the content of an Emoji Suggester */ calculateEmojiSuggestion() { + if (this.shouldBlockEmojiCalc) { + this.shouldBlockEmojiCalc = false; + return; + } + const leftString = this.state.value.substring(0, this.state.selection.end); const colonIndex = leftString.lastIndexOf(':'); const isCurrentlyShowingEmojiSuggestion = this.isEmojiCode(this.state.value, this.state.selection.end); @@ -544,6 +542,11 @@ class ReportActionCompose extends React.Component { } calculateMentionSuggestion() { + if (this.shouldBlockMentionCalc) { + this.shouldBlockMentionCalc = false; + return; + } + const valueAfterTheCursor = this.state.value.substring(this.state.selection.end); const indexOfFirstWhitespaceCharOrEmojiAfterTheCursor = valueAfterTheCursor.search(CONST.REGEX.SPECIAL_CHAR_OR_EMOJI); @@ -945,7 +948,8 @@ class ReportActionCompose extends React.Component { onConfirm={this.addAttachment} onModalShow={() => this.setState({isAttachmentPreviewActive: true})} onModalHide={() => { - this.shouldBlockSuggestionsCalc = false; + this.shouldBlockEmojiCalc = false; + this.shouldBlockMentionCalc = false; this.setState({isAttachmentPreviewActive: false}); }} > @@ -1026,10 +1030,11 @@ class ReportActionCompose extends React.Component { icon: Expensicons.Paperclip, text: this.props.translate('reportActionCompose.addAttachment'), onSelected: () => { - // Set a flag to block emoji calculation until we're finished using the file picker, + // Set a flag to block suggestion calculation until we're finished using the file picker, // which will stop any flickering as the file picker opens on non-native devices. if (this.willBlurTextInputOnTapOutside) { - this.shouldBlockSuggestionsCalc = true; + this.shouldBlockEmojiCalc = true; + this.shouldBlockMentionCalc = true; } openPicker({ @@ -1084,8 +1089,8 @@ class ReportActionCompose extends React.Component { this.resetSuggestions(); }} onClick={() => { - this.shouldBlockSuggestionsCalc = false; - this.onSelectionChange(); + this.shouldBlockEmojiCalc = false + this.shouldBlockMentionCalc = false; }} onPasteFile={displayFileInModal} shouldClear={this.state.textInputShouldClear} From 495d71540641055a2c69ea30dbee36e3afc97ee6 Mon Sep 17 00:00:00 2001 From: Sujit Kumar <60378235+therealsujitk@users.noreply.github.com> Date: Fri, 26 May 2023 20:34:35 +0530 Subject: [PATCH 372/751] Add missing semicolon --- src/pages/home/report/ReportActionCompose.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index 55ea4f485706..8fdb715a345a 100644 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -1089,7 +1089,7 @@ class ReportActionCompose extends React.Component { this.resetSuggestions(); }} onClick={() => { - this.shouldBlockEmojiCalc = false + this.shouldBlockEmojiCalc = false; this.shouldBlockMentionCalc = false; }} onPasteFile={displayFileInModal} From 510e77df45238d9873efdf65bdd8e481365ddb01 Mon Sep 17 00:00:00 2001 From: tienifr Date: Fri, 26 May 2023 22:33:20 +0700 Subject: [PATCH 373/751] fix: refactor --- src/components/TextInput/BaseTextInput.js | 4 ++-- src/libs/isInputAutofilled.js | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/components/TextInput/BaseTextInput.js b/src/components/TextInput/BaseTextInput.js index 1a6eec10fb7d..64e4da77ec43 100644 --- a/src/components/TextInput/BaseTextInput.js +++ b/src/components/TextInput/BaseTextInput.js @@ -17,6 +17,7 @@ import Checkbox from '../Checkbox'; import getSecureEntryKeyboardType from '../../libs/getSecureEntryKeyboardType'; import CONST from '../../CONST'; import FormHelpMessage from '../FormHelpMessage'; +import isInputAutoFilled from '../../libs/isInputAutoFilled'; class BaseTextInput extends Component { constructor(props) { @@ -131,8 +132,7 @@ class BaseTextInput extends Component { // If the text has been supplied by Chrome autofill, the value state is not synced with the value // as Chrome doesn't trigger a change event. When there is autofill text, don't deactivate label. - const textWasAutoFilledOnChrome = this.input.matches && this.input.matches(':-webkit-autofill'); - if (!textWasAutoFilledOnChrome) { + if (!isInputAutoFilled(this.input)) { this.deactivateLabel(); } } diff --git a/src/libs/isInputAutofilled.js b/src/libs/isInputAutofilled.js index 56fda5ce477e..3a64ffd441ee 100644 --- a/src/libs/isInputAutofilled.js +++ b/src/libs/isInputAutofilled.js @@ -3,9 +3,7 @@ * @param {Object} input * @return {Boolean} */ -function isInputAutoFilled(input) { +export default function isInputAutoFilled(input) { if (!input.matches) return false; return input.matches(':-webkit-autofill') || input.matches(':autofill'); } - -export default isInputAutoFilled; From f6301e61a24a8c9479e704828179c204cd60afe8 Mon Sep 17 00:00:00 2001 From: tienifr Date: Fri, 26 May 2023 22:41:43 +0700 Subject: [PATCH 374/751] fix: change file name --- src/libs/isInputAutoFilled.js | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/libs/isInputAutoFilled.js diff --git a/src/libs/isInputAutoFilled.js b/src/libs/isInputAutoFilled.js new file mode 100644 index 000000000000..3a64ffd441ee --- /dev/null +++ b/src/libs/isInputAutoFilled.js @@ -0,0 +1,9 @@ +/** + * Check the input is auto filled or not + * @param {Object} input + * @return {Boolean} + */ +export default function isInputAutoFilled(input) { + if (!input.matches) return false; + return input.matches(':-webkit-autofill') || input.matches(':autofill'); +} From 3530d39d9e354f565d5ecdacdd868557e4a67697 Mon Sep 17 00:00:00 2001 From: tienifr Date: Fri, 26 May 2023 22:43:44 +0700 Subject: [PATCH 375/751] remove unnecessary file --- src/libs/isInputAutofilled.js | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 src/libs/isInputAutofilled.js diff --git a/src/libs/isInputAutofilled.js b/src/libs/isInputAutofilled.js deleted file mode 100644 index 3a64ffd441ee..000000000000 --- a/src/libs/isInputAutofilled.js +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Check the input is auto filled or not - * @param {Object} input - * @return {Boolean} - */ -export default function isInputAutoFilled(input) { - if (!input.matches) return false; - return input.matches(':-webkit-autofill') || input.matches(':autofill'); -} From 3fef47164eee1d14add6d7aed7461002e50c099f Mon Sep 17 00:00:00 2001 From: Konrad Bochnia Date: Fri, 26 May 2023 17:44:36 +0200 Subject: [PATCH 376/751] Fix lint and prettier --- src/components/ExceededCommentLength.js | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/components/ExceededCommentLength.js b/src/components/ExceededCommentLength.js index 9c39ae760a2a..c403aa63c172 100644 --- a/src/components/ExceededCommentLength.js +++ b/src/components/ExceededCommentLength.js @@ -19,26 +19,22 @@ function ExceededCommentLength(props) { const updateCommentLength = useMemo( () => debounce((comment, onExceededMaxCommentLength) => { - const commentLength = ReportUtils.getCommentLength(comment); - setCommentLength(commentLength); - onExceededMaxCommentLength(commentLength > CONST.MAX_COMMENT_LENGTH); + const newCommentLength = ReportUtils.getCommentLength(comment); + setCommentLength(newCommentLength); + onExceededMaxCommentLength(newCommentLength > CONST.MAX_COMMENT_LENGTH); }, CONST.TIMING.COMMENT_LENGTH_DEBOUNCE_TIME), [], ); - + useEffect(() => { updateCommentLength(props.comment, props.onExceededMaxCommentLength); - }, [props.comment, props.onExceededMaxCommentLength]) + }, [props.comment, props.onExceededMaxCommentLength, updateCommentLength]); if (commentLength <= CONST.MAX_COMMENT_LENGTH) { return null; } - return ( - - {`${commentLength}/${CONST.MAX_COMMENT_LENGTH}`} - - ); + return {`${commentLength}/${CONST.MAX_COMMENT_LENGTH}`}; } ExceededCommentLength.propTypes = propTypes; From 41076fbb78dc81608305d9d9de242c4b2ecb9acb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Ch=C3=A1vez?= Date: Fri, 26 May 2023 10:23:36 -0600 Subject: [PATCH 377/751] sign out for not allowed actions for anonymous users --- .../BaseVideoChatButtonAndMenu.js | 31 +++++++++-- .../videoChatButtonAndMenuPropTypes.js | 1 + src/pages/ReportDetailsPage.js | 19 ++++++- src/pages/home/HeaderView.js | 13 ++++- .../BaseReportActionContextMenu.js | 53 ++++++++++++++++--- src/pages/home/report/ReportActionItem.js | 28 ++++++++-- .../FloatingActionButtonAndPopover.js | 45 ++++++++++++---- 7 files changed, 165 insertions(+), 25 deletions(-) diff --git a/src/components/VideoChatButtonAndMenu/BaseVideoChatButtonAndMenu.js b/src/components/VideoChatButtonAndMenu/BaseVideoChatButtonAndMenu.js index aac6043e7e97..e7574b756721 100755 --- a/src/components/VideoChatButtonAndMenu/BaseVideoChatButtonAndMenu.js +++ b/src/components/VideoChatButtonAndMenu/BaseVideoChatButtonAndMenu.js @@ -2,6 +2,7 @@ import _ from 'underscore'; import React, {Component} from 'react'; import {View, Pressable, Dimensions, Linking} from 'react-native'; import PropTypes from 'prop-types'; +import {withOnyx} from 'react-native-onyx'; import Icon from '../Icon'; import * as Expensicons from '../Icon/Expensicons'; import Popover from '../Popover'; @@ -16,14 +17,22 @@ import withLocalize, {withLocalizePropTypes} from '../withLocalize'; import compose from '../../libs/compose'; import Tooltip from '../Tooltip'; import {propTypes as videoChatButtonAndMenuPropTypes, defaultProps} from './videoChatButtonAndMenuPropTypes'; +import * as SessionUtils from '../../libs/SessionUtils'; +import * as Session from '../../libs/actions/Session'; +import ONYXKEYS from '../../ONYXKEYS'; const propTypes = { - /** Link to open when user wants to create a new google meet meeting */ - googleMeetURL: PropTypes.string.isRequired, - ...videoChatButtonAndMenuPropTypes, ...withLocalizePropTypes, ...windowDimensionsPropTypes, + + /** Link to open when user wants to create a new google meet meeting */ + googleMeetURL: PropTypes.string.isRequired, + + session: PropTypes.shape({ + /** Determines if user is anonymous or not */ + authTokenType: PropTypes.string, + }), }; class BaseVideoChatButtonAndMenu extends Component { @@ -107,6 +116,12 @@ class BaseVideoChatButtonAndMenu extends Component { // Drop focus to avoid blue focus ring. this.videoChatButton.blur(); + // If user is anonymous, show the sign in modal + if (SessionUtils.isAnonymousUser(this.props.session.authTokenType)) { + Session.signOutAndRedirectToSignIn(); + return; + } + // If this is the Concierge chat, we'll open the modal for requesting a setup call instead if (this.props.isConcierge && this.props.guideCalendarLink) { Linking.openURL(this.props.guideCalendarLink); @@ -151,4 +166,12 @@ class BaseVideoChatButtonAndMenu extends Component { BaseVideoChatButtonAndMenu.propTypes = propTypes; BaseVideoChatButtonAndMenu.defaultProps = defaultProps; -export default compose(withWindowDimensions, withLocalize)(BaseVideoChatButtonAndMenu); +export default compose( + withWindowDimensions, + withLocalize, + withOnyx({ + session: { + key: ONYXKEYS.SESSION, + }, + }), +)(BaseVideoChatButtonAndMenu); diff --git a/src/components/VideoChatButtonAndMenu/videoChatButtonAndMenuPropTypes.js b/src/components/VideoChatButtonAndMenu/videoChatButtonAndMenuPropTypes.js index d791bed33c7f..2bf858460dd4 100644 --- a/src/components/VideoChatButtonAndMenu/videoChatButtonAndMenuPropTypes.js +++ b/src/components/VideoChatButtonAndMenu/videoChatButtonAndMenuPropTypes.js @@ -11,6 +11,7 @@ const propTypes = { const defaultProps = { isConcierge: false, guideCalendarLink: null, + session: {}, }; export {propTypes, defaultProps}; diff --git a/src/pages/ReportDetailsPage.js b/src/pages/ReportDetailsPage.js index f073abbb2616..e88a8a562318 100644 --- a/src/pages/ReportDetailsPage.js +++ b/src/pages/ReportDetailsPage.js @@ -17,6 +17,8 @@ import * as OptionsListUtils from '../libs/OptionsListUtils'; import * as ReportUtils from '../libs/ReportUtils'; import * as PolicyUtils from '../libs/PolicyUtils'; import * as Report from '../libs/actions/Report'; +import * as Session from '../libs/actions/Session'; +import * as SessionUtils from '../libs/SessionUtils'; import participantPropTypes from '../components/participantPropTypes'; import * as Expensicons from '../components/Icon/Expensicons'; import ROUTES from '../ROUTES'; @@ -49,11 +51,17 @@ const propTypes = { /** Personal details of all the users */ personalDetails: PropTypes.objectOf(participantPropTypes), + + session: PropTypes.shape({ + /** Determines if user is anonymous or not */ + authTokenType: PropTypes.string, + }), }; const defaultProps = { policies: {}, personalDetails: {}, + session: {}, }; class ReportDetailsPage extends Component { @@ -181,7 +189,13 @@ class ReportDetailsPage extends Component { title={this.props.translate(item.translationKey)} subtitle={item.subtitle} icon={item.icon} - onPress={item.action} + onPress={() => { + if (SessionUtils.isAnonymousUser(this.props.session.authTokenType)) { + Session.signOutAndRedirectToSignIn(); + } else { + item.action(); + } + }} shouldShowRightIcon brickRoadIndicator={brickRoadIndicator} /> @@ -206,5 +220,8 @@ export default compose( policies: { key: ONYXKEYS.COLLECTION.POLICY, }, + session: { + key: ONYXKEYS.SESSION, + }, }), )(ReportDetailsPage); diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index 42e6fb64f1e2..ac03c98c6db9 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -28,6 +28,8 @@ import ONYXKEYS from '../../ONYXKEYS'; import ThreeDotsMenu from '../../components/ThreeDotsMenu'; import * as Task from '../../libs/actions/Task'; import reportActionPropTypes from './report/reportActionPropTypes'; +import * as SessionUtils from '../../libs/SessionUtils'; +import * as Session from '../../libs/actions/Session'; const propTypes = { /** Toggles the navigationMenu open and closed */ @@ -197,7 +199,13 @@ const HeaderView = (props) => { )} Report.togglePinnedState(props.report)} + onPress={() => { + if (SessionUtils.isAnonymousUser(props.session.authTokenType)) { + Session.signOutAndRedirectToSignIn(); + } else { + Report.togglePinnedState(props.report); + } + }} style={[styles.touchableButtonImage]} > `${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID || report.reportID}`, }, + session: { + key: ONYXKEYS.SESSION, + }, }), )(HeaderView); diff --git a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js index d307d06b7984..99e11e70f5c8 100755 --- a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js +++ b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js @@ -1,7 +1,8 @@ import React from 'react'; -import {View} from 'react-native'; +import {InteractionManager, View} from 'react-native'; import _ from 'underscore'; import PropTypes from 'prop-types'; +import {withOnyx} from 'react-native-onyx'; import getReportActionContextMenuStyles from '../../../../styles/getReportActionContextMenuStyles'; import ContextMenuItem from '../../../../components/ContextMenuItem'; import {propTypes as genericReportActionContextMenuPropTypes, defaultProps as GenericReportActionContextMenuDefaultProps} from './genericReportActionContextMenuPropTypes'; @@ -10,8 +11,16 @@ import ContextMenuActions, {CONTEXT_MENU_TYPES} from './ContextMenuActions'; import compose from '../../../../libs/compose'; import withWindowDimensions, {windowDimensionsPropTypes} from '../../../../components/withWindowDimensions'; import {withBetas} from '../../../../components/OnyxProvider'; +import ONYXKEYS from '../../../../ONYXKEYS'; +import * as SessionUtils from '../../../../libs/SessionUtils'; +import * as Session from '../../../../libs/actions/Session'; +import {hideContextMenu} from './ReportActionContextMenu'; const propTypes = { + ...genericReportActionContextMenuPropTypes, + ...withLocalizePropTypes, + ...windowDimensionsPropTypes, + /** String representing the context menu type [LINK, REPORT_ACTION] which controls context menu choices */ type: PropTypes.string, @@ -26,18 +35,20 @@ const propTypes = { contentRef: PropTypes.oneOfType([PropTypes.node, PropTypes.object, PropTypes.func]), - ...genericReportActionContextMenuPropTypes, - ...withLocalizePropTypes, - ...windowDimensionsPropTypes, + session: PropTypes.shape({ + /** Determines if user is anonymous or not */ + authTokenType: PropTypes.string, + }), }; const defaultProps = { + ...GenericReportActionContextMenuDefaultProps, type: CONTEXT_MENU_TYPES.REPORT_ACTION, anchor: null, contentRef: null, isChronosReport: false, isArchivedRoom: false, - ...GenericReportActionContextMenuDefaultProps, + session: {}, }; class BaseReportActionContextMenu extends React.Component { constructor(props) { @@ -61,6 +72,24 @@ class BaseReportActionContextMenu extends React.Component { this.props.reportID, ); + /** + * Checks if user is anonymous. If true, hides the context menu and + * shows the sign in modal. Else, executes the callback. + * + * @param {Function} callback + */ + const interceptAnonymousUser = (callback) => { + if (SessionUtils.isAnonymousUser(this.props.session.authTokenType)) { + hideContextMenu(false); + + InteractionManager.runAfterInteractions(() => { + Session.signOutAndRedirectToSignIn(); + }); + } else { + callback(); + } + }; + return ( (this.props.isVisible || this.state.shouldKeepOpen) && ( this.setState({shouldKeepOpen: false}), openContextMenu: () => this.setState({shouldKeepOpen: true}), + interceptAnonymousUser, }; if (contextAction.renderContent) { @@ -95,7 +125,7 @@ class BaseReportActionContextMenu extends React.Component { successText={contextAction.successTextTranslateKey ? this.props.translate(contextAction.successTextTranslateKey) : undefined} isMini={this.props.isMini} key={contextAction.textTranslateKey} - onPress={() => contextAction.onPress(closePopup, payload)} + onPress={() => interceptAnonymousUser(() => contextAction.onPress(closePopup, payload))} description={contextAction.getDescription(this.props.selection, this.props.isSmallScreenWidth)} autoReset={contextAction.autoReset} /> @@ -110,4 +140,13 @@ class BaseReportActionContextMenu extends React.Component { BaseReportActionContextMenu.propTypes = propTypes; BaseReportActionContextMenu.defaultProps = defaultProps; -export default compose(withLocalize, withBetas(), withWindowDimensions)(BaseReportActionContextMenu); +export default compose( + withLocalize, + withBetas(), + withWindowDimensions, + withOnyx({ + session: { + key: ONYXKEYS.SESSION, + }, + }), +)(BaseReportActionContextMenu); diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index 5b44f3fa0ed6..bada391b2dab 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -1,7 +1,7 @@ import _ from 'underscore'; import lodashGet from 'lodash/get'; import React, {useState, useRef, useEffect, memo, useCallback} from 'react'; -import {View} from 'react-native'; +import {InteractionManager, View} from 'react-native'; import PropTypes from 'prop-types'; import {withOnyx} from 'react-native-onyx'; import CONST from '../../../CONST'; @@ -52,8 +52,13 @@ import ReportActionItemDraft from './ReportActionItemDraft'; import TaskPreview from '../../../components/ReportActionItem/TaskPreview'; import TaskAction from '../../../components/ReportActionItem/TaskAction'; import Permissions from '../../../libs/Permissions'; +import * as SessionUtils from '../../../libs/SessionUtils'; +import * as Session from '../../../libs/actions/Session'; +import {hideContextMenu} from './ContextMenu/ReportActionContextMenu'; const propTypes = { + ...windowDimensionsPropTypes, + /** Report for this action */ report: reportPropTypes.isRequired, @@ -91,7 +96,10 @@ const propTypes = { /** List of betas available to current user */ betas: PropTypes.arrayOf(PropTypes.string), - ...windowDimensionsPropTypes, + session: PropTypes.shape({ + /** Determines if user is anonymous or not */ + authTokenType: PropTypes.string, + }), }; const defaultProps = { @@ -101,6 +109,7 @@ const defaultProps = { shouldShowSubscriptAvatar: false, hasOutstandingIOU: false, betas: [], + session: {}, }; function ReportActionItem(props) { @@ -281,7 +290,17 @@ function ReportActionItem(props) { { + if (SessionUtils.isAnonymousUser(props.session.authTokenType)) { + hideContextMenu(false); + + InteractionManager.runAfterInteractions(() => { + Session.signOutAndRedirectToSignIn(); + }); + } else { + toggleReaction(emoji); + } + }} /> )} @@ -444,6 +463,9 @@ export default compose( betas: { key: ONYXKEYS.BETAS, }, + session: { + key: ONYXKEYS.SESSION, + }, }), )( memo( diff --git a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js index 6c0dd2cf6cd5..5956bf97d2a9 100644 --- a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js +++ b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js @@ -22,6 +22,8 @@ import * as Welcome from '../../../../libs/actions/Welcome'; import withNavigationFocus from '../../../../components/withNavigationFocus'; import withDrawerState from '../../../../components/withDrawerState'; import * as TaskUtils from '../../../../libs/actions/Task'; +import * as SessionUtils from '../../../../libs/SessionUtils'; +import * as Session from '../../../../libs/actions/Session'; /** * @param {Object} [policy] @@ -34,6 +36,8 @@ const policySelector = (policy) => }; const propTypes = { + ...withLocalizePropTypes, + /* Callback function when the menu is shown */ onShowCreateMenu: PropTypes.func, @@ -52,7 +56,10 @@ const propTypes = { /** Indicated whether the report data is loading */ isLoading: PropTypes.bool, - ...withLocalizePropTypes, + session: PropTypes.shape({ + /** Determines if user is anonymous or not */ + authTokenType: PropTypes.string, + }), }; const defaultProps = { onHideCreateMenu: () => {}, @@ -60,6 +67,7 @@ const defaultProps = { allPolicies: {}, betas: [], isLoading: false, + session: {}, }; /** @@ -72,9 +80,11 @@ class FloatingActionButtonAndPopover extends React.Component { this.showCreateMenu = this.showCreateMenu.bind(this); this.hideCreateMenu = this.hideCreateMenu.bind(this); + this.interceptAnonymousUser = this.interceptAnonymousUser.bind(this); this.state = { isCreateMenuActive: false, + isAnonymousUser: SessionUtils.isAnonymousUser(props.session.authTokenType), }; } @@ -162,6 +172,20 @@ class FloatingActionButtonAndPopover extends React.Component { }); } + /** + * Checks if user is anonymous. If true, shows the sign in modal, else, + * executes the callback. + * + * @param {Function} callback + */ + interceptAnonymousUser(callback) { + if (this.state.isAnonymousUser) { + Session.signOutAndRedirectToSignIn(); + } else { + callback(); + } + } + render() { // Workspaces are policies with type === 'free' const workspaces = _.filter(this.props.allPolicies, (policy) => policy && policy.type === CONST.POLICY.TYPE.FREE); @@ -178,19 +202,19 @@ class FloatingActionButtonAndPopover extends React.Component { { icon: Expensicons.ChatBubble, text: this.props.translate('sidebarScreen.newChat'), - onSelected: () => Navigation.navigate(ROUTES.NEW_CHAT), + onSelected: () => this.interceptAnonymousUser(() => Navigation.navigate(ROUTES.NEW_CHAT)), }, { icon: Expensicons.Users, text: this.props.translate('sidebarScreen.newGroup'), - onSelected: () => Navigation.navigate(ROUTES.NEW_GROUP), + onSelected: () => this.interceptAnonymousUser(() => Navigation.navigate(ROUTES.NEW_GROUP)), }, ...(Permissions.canUsePolicyRooms(this.props.betas) && workspaces.length ? [ { icon: Expensicons.Hashtag, text: this.props.translate('sidebarScreen.newRoom'), - onSelected: () => Navigation.navigate(ROUTES.WORKSPACE_NEW_ROOM), + onSelected: () => this.interceptAnonymousUser(() => Navigation.navigate(ROUTES.WORKSPACE_NEW_ROOM)), }, ] : []), @@ -199,7 +223,7 @@ class FloatingActionButtonAndPopover extends React.Component { { icon: Expensicons.Send, text: this.props.translate('iou.sendMoney'), - onSelected: () => Navigation.navigate(ROUTES.IOU_SEND), + onSelected: () => this.interceptAnonymousUser(() => Navigation.navigate(ROUTES.IOU_SEND)), }, ] : []), @@ -208,7 +232,7 @@ class FloatingActionButtonAndPopover extends React.Component { { icon: Expensicons.MoneyCircle, text: this.props.translate('iou.requestMoney'), - onSelected: () => Navigation.navigate(ROUTES.IOU_REQUEST), + onSelected: () => this.interceptAnonymousUser(() => Navigation.navigate(ROUTES.IOU_REQUEST)), }, ] : []), @@ -217,7 +241,7 @@ class FloatingActionButtonAndPopover extends React.Component { { icon: Expensicons.Receipt, text: this.props.translate('iou.splitBill'), - onSelected: () => Navigation.navigate(ROUTES.IOU_BILL), + onSelected: () => this.interceptAnonymousUser(() => Navigation.navigate(ROUTES.IOU_BILL)), }, ] : []), @@ -226,7 +250,7 @@ class FloatingActionButtonAndPopover extends React.Component { { icon: Expensicons.Task, text: this.props.translate('newTaskPage.assignTask'), - onSelected: () => TaskUtils.clearOutTaskInfoAndNavigate(), + onSelected: () => this.interceptAnonymousUser(() => TaskUtils.clearOutTaskInfoAndNavigate()), }, ] : []), @@ -238,7 +262,7 @@ class FloatingActionButtonAndPopover extends React.Component { iconHeight: 40, text: this.props.translate('workspace.new.newWorkspace'), description: this.props.translate('workspace.new.getTheExpensifyCardAndMore'), - onSelected: () => Policy.createWorkspace(), + onSelected: () => this.interceptAnonymousUser(() => Policy.createWorkspace()), }, ] : []), @@ -265,6 +289,9 @@ export default compose( withDrawerState, withWindowDimensions, withOnyx({ + session: { + key: ONYXKEYS.SESSION, + }, allPolicies: { key: ONYXKEYS.COLLECTION.POLICY, selector: policySelector, From e21c085dd0acb4482577a6fa699ccd3444a32ef3 Mon Sep 17 00:00:00 2001 From: Daniel Gale-Rosen Date: Fri, 26 May 2023 12:25:57 -0400 Subject: [PATCH 378/751] add context menu action --- assets/images/flag.svg | 7 +++++++ src/components/Icon/Expensicons.js | 2 ++ src/languages/en.js | 1 + src/languages/es.js | 1 + src/libs/ReportUtils.js | 20 +++++++++++++++++++ .../report/ContextMenu/ContextMenuActions.js | 19 ++++++++++++++++++ 6 files changed, 50 insertions(+) create mode 100644 assets/images/flag.svg diff --git a/assets/images/flag.svg b/assets/images/flag.svg new file mode 100644 index 000000000000..9b6737459fbd --- /dev/null +++ b/assets/images/flag.svg @@ -0,0 +1,7 @@ + + + + + diff --git a/src/components/Icon/Expensicons.js b/src/components/Icon/Expensicons.js index 89fa057aa8d2..db093d2bc4df 100644 --- a/src/components/Icon/Expensicons.js +++ b/src/components/Icon/Expensicons.js @@ -41,6 +41,7 @@ import ExpensifyWordmark from '../../../assets/images/expensify-wordmark.svg'; import Expand from '../../../assets/images/expand.svg'; import Eye from '../../../assets/images/eye.svg'; import EyeDisabled from '../../../assets/images/eye-disabled.svg'; +import Flag from '../../../assets/images/flag.svg'; import FlagLevelOne from '../../../assets/images/flag_level_01.svg'; import FlagLevelTwo from '../../../assets/images/flag_level_02.svg'; import FlagLevelThree from '../../../assets/images/flag_level_03.svg'; @@ -165,6 +166,7 @@ export { EyeDisabled, FallbackAvatar, FallbackWorkspaceAvatar, + Flag, FlagLevelOne, FlagLevelTwo, FlagLevelThree, diff --git a/src/languages/en.js b/src/languages/en.js index 9f4426a2a441..72801acdd357 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -261,6 +261,7 @@ export default { deleteConfirmation: ({action}) => `Are you sure you want to delete this ${ReportActionsUtils.isMoneyRequestAction(action) ? 'request' : 'comment'}?`, onlyVisible: 'Only visible to', replyInThread: 'Reply in thread', + flagAsOffensive: 'Flag as offensive', }, emojiReactions: { addReactionTooltip: 'Add reaction', diff --git a/src/languages/es.js b/src/languages/es.js index 8a024d2f3e8a..1b9a885ca8bf 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -260,6 +260,7 @@ export default { deleteConfirmation: ({action}) => `¿Estás seguro de que quieres eliminar este ${ReportActionsUtils.isMoneyRequestAction(action) ? 'pedido' : 'comentario'}`, onlyVisible: 'Visible sólo para', replyInThread: 'Responder en el hilo', + flagAsOffensive: 'Marcar como ofensivo', }, emojiReactions: { addReactionTooltip: 'Añadir una reacción', diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 6122701476f7..cb8210395933 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -193,6 +193,25 @@ function canEditReportAction(reportAction) { ); } +/** + * Can only flag if: + * + * - It was written by someone else + * - It's an ADDCOMMENT that is not an attachment + * + * @param {Object} reportAction + * @returns {Boolean} + */ +function canFlagReportAction(reportAction) { + return ( + reportAction.actorEmail !== sessionEmail && + reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT && + !isReportMessageAttachment(lodashGet(reportAction, ['message', 0], {})) && + !ReportActionsUtils.isDeletedAction(reportAction) && + !ReportActionsUtils.isCreatedTaskReportAction(reportAction) + ); +} + /** * Whether the Money Request report is settled * @@ -2218,6 +2237,7 @@ export { isReportMessageAttachment, findLastAccessedReport, canEditReportAction, + canFlagReportAction, canDeleteReportAction, canLeaveRoom, sortReportsByLastRead, diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index 300d689aea52..5dd598342c83 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -19,6 +19,8 @@ import * as Environment from '../../../../libs/Environment/Environment'; import Permissions from '../../../../libs/Permissions'; import QuickEmojiReactions from '../../../../components/Reactions/QuickEmojiReactions'; import MiniQuickEmojiReactions from '../../../../components/Reactions/MiniQuickEmojiReactions'; +import Navigation from '../../../../libs/Navigation/Navigation'; +import ROUTES from '../../../../ROUTES'; /** * Gets the HTML version of the message in an action. @@ -264,6 +266,23 @@ export default [ }, getDescription: () => {}, }, + { + textTranslateKey: 'reportActionContextMenu.flagAsOffensive', + icon: Expensicons.Flag, + shouldShow: (type, reportAction, isArchivedRoom, betas, menuTarget, isChronosReport, reportID) => + type === CONTEXT_MENU_TYPES.REPORT_ACTION && ReportUtils.canFlagReportAction(reportAction, reportID) && !isArchivedRoom && !isChronosReport && !ReportUtils.isConciergeChatReport(reportID), + onPress: (closePopover, {reportID, reportAction}) => { + if (closePopover) { + hideContextMenu( + false, + () => Navigation.navigate(ROUTES.getFlagCommentRoute(reportID, reportAction.reportActionID)) + ); + } + + Navigation.navigate(ROUTES.getFlagCommentRoute(reportID, reportAction.reportActionID)) + }, + getDescription: () => {}, + }, ]; export {CONTEXT_MENU_TYPES}; From ee1bc80af3f033fd8ec14923caae8869188be604 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Ch=C3=A1vez?= Date: Fri, 26 May 2023 10:26:13 -0600 Subject: [PATCH 379/751] add isAnonymousUser function --- src/libs/SessionUtils.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/libs/SessionUtils.js b/src/libs/SessionUtils.js index 875b540e5599..7b006ce76f76 100644 --- a/src/libs/SessionUtils.js +++ b/src/libs/SessionUtils.js @@ -28,7 +28,18 @@ function isLoggingInAsNewUser(transitionURL, sessionEmail) { return linkedEmail !== sessionEmail; } +/** + * Checks if the account is an anonymous account. + * + * @param {string} authTokenType from Session object + * @return {boolean} + */ +function isAnonymousUser(authTokenType) { + return authTokenType === 'anonymousAccount'; +} + export { // eslint-disable-next-line import/prefer-default-export isLoggingInAsNewUser, + isAnonymousUser, }; From 5024d66a854cd6dede6271c878a63b2e9d2ebb5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Ch=C3=A1vez?= Date: Fri, 26 May 2023 10:33:07 -0600 Subject: [PATCH 380/751] sign out in search and avatar --- src/pages/home/sidebar/SidebarLinks.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/pages/home/sidebar/SidebarLinks.js b/src/pages/home/sidebar/SidebarLinks.js index d48ca795a3e8..1b79d16f1e58 100644 --- a/src/pages/home/sidebar/SidebarLinks.js +++ b/src/pages/home/sidebar/SidebarLinks.js @@ -34,6 +34,8 @@ import defaultTheme from '../../../styles/themes/default'; import OptionsListSkeletonView from '../../../components/OptionsListSkeletonView'; import variables from '../../../styles/variables'; import LogoComponent from '../../../../assets/images/expensify-wordmark.svg'; +import * as SessionUtils from '../../../libs/SessionUtils'; +import * as Session from '../../../libs/actions/Session'; const propTypes = { /** Toggles the navigation menu open and closed */ @@ -107,7 +109,11 @@ class SidebarLinks extends React.Component { // Prevent opening Search page when click Search icon quickly after clicking FAB icon return; } - Navigation.navigate(ROUTES.SEARCH); + if (SessionUtils.isAnonymousUser(this.props.session.authTokenType)) { + Session.signOutAndRedirectToSignIn(); + } else { + Navigation.navigate(ROUTES.SEARCH); + } } showSettingsPage() { @@ -115,7 +121,11 @@ class SidebarLinks extends React.Component { // Prevent opening Settings page when click profile avatar quickly after clicking FAB icon return; } - Navigation.navigate(ROUTES.SETTINGS); + if (SessionUtils.isAnonymousUser(this.props.session.authTokenType)) { + Session.signOutAndRedirectToSignIn(); + } else { + Navigation.navigate(ROUTES.SETTINGS); + } } /** From f34eb605165ce6f682753b00a0361b3ef6b66017 Mon Sep 17 00:00:00 2001 From: someone-here Date: Fri, 26 May 2023 22:14:07 +0530 Subject: [PATCH 381/751] Reverting EmojiPicker Animation --- src/components/EmojiPicker/EmojiPicker.js | 4 ++++ src/components/Modal/index.ios.js | 2 -- src/pages/home/report/ReactionList/PopoverReactionList.js | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/EmojiPicker/EmojiPicker.js b/src/components/EmojiPicker/EmojiPicker.js index 000b8f33ed04..1e15e9e20bf3 100644 --- a/src/components/EmojiPicker/EmojiPicker.js +++ b/src/components/EmojiPicker/EmojiPicker.js @@ -141,6 +141,8 @@ class EmojiPicker extends React.Component { } render() { + // There is no way to disable animations and they are really laggy, because there are so many + // emojis. The best alternative is to set it to 1ms so it just "pops" in and out return ( ( {props.children} diff --git a/src/pages/home/report/ReactionList/PopoverReactionList.js b/src/pages/home/report/ReactionList/PopoverReactionList.js index b6e5813a947f..ba36c1ce09ff 100644 --- a/src/pages/home/report/ReactionList/PopoverReactionList.js +++ b/src/pages/home/report/ReactionList/PopoverReactionList.js @@ -247,6 +247,7 @@ class PopoverReactionList extends React.Component { anchorPosition={this.state.popoverAnchorPosition} animationIn="fadeIn" disableAnimation={false} + animationOutTiming={1} shouldSetModalVisibility={false} fullscreen > From 52b5306722245a032b0e3d0518543070c1ced789 Mon Sep 17 00:00:00 2001 From: Daniel Gale-Rosen Date: Fri, 26 May 2023 13:07:18 -0400 Subject: [PATCH 382/751] add translations --- src/languages/en.js | 16 ++++++++++++++++ src/languages/es.js | 16 ++++++++++++++++ src/pages/FlagCommentPage.js | 33 +++++++++++++++------------------ 3 files changed, 47 insertions(+), 18 deletions(-) diff --git a/src/languages/en.js b/src/languages/en.js index 2a0534a9746e..5493eae81e2e 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -1401,4 +1401,20 @@ export default { copyUrlToClipboard: 'Copy URL to clipboard', copied: 'Copied!', }, + moderation: { + flagDescription: 'All flagged messages will be sent to a moderator for review. If a message is flagged at a level above Spam or Inconsiderate, it will immediately be hidden. Users may, however, choose to reveal the message while it is being reviewed if they choose. Dependent on the decision of the moderator, the message may or may not be permanently hidden or deleted, and the sender may be banned from posting temporarily or permanently.', + chooseAReason: 'Choose a reason below:', + spam: 'Spam', + spamDescription: 'Unsolicited off-topic promotion', + inconsiderate: 'Inconsiderate', + inconsiderateDescription: 'Insulting or disrespectful phrasing, with questionable intentions', + intimidation: 'Intimidation', + intimidationDescription: 'Aggressively pursuing an agenda over valid objections', + bullying: 'Bullying', + bullyingDescription: 'Targeting an individual to obtain obedience', + harassment: 'Harassment', + harassmentDescription: 'Racist, misogynistic, or other broadly discriminatory behavior', + assault: 'Assault', + assaultDescription: 'Specifically targeted emotional attack with the intention of harm', + } }; diff --git a/src/languages/es.js b/src/languages/es.js index 0eda68462800..381f534eaeab 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -1867,4 +1867,20 @@ export default { copyUrlToClipboard: 'Copiar URL al portapapeles', copied: '¡Copiado!', }, + moderation: { + flagDescription: 'Todos los mensajes marcados se enviarán a un moderador para su revisión. Si un mensaje se marca en un nivel superior a Spam o Desconsiderado, se ocultará de inmediato. Sin embargo, los usuarios pueden optar por revelar el mensaje mientras se revisa si así lo desean. Dependiendo de la decisión del moderador, el mensaje puede ocultarse o eliminarse permanentemente o no, y el remitente puede tener prohibido enviar mensajes de forma temporal o permanente.', + chooseAReason: 'Elige un motivo de abajo', + spam: 'Spam', + spamDescription: 'Promoción fuera de tema no solicitada', + inconsiderate: 'Desconsiderado', + inconsiderateDescription: 'Frase insultante o irrespetuosa, con intenciones cuestionables', + intimidation: 'Intimidación', + intimidationDescription: 'Persigue agresivamente una agenda sobre objeciones válidas', + bullying: 'Bullying', + bullyingDescription: 'Apunta a un individuo para obtener obediencia.', + harassment: 'Acoso', + harassmentDescription: 'Comportamiento racista, misógino u otro comportamiento ampliamente discriminatorio', + assault: 'Agresion', + assaultDescription: 'Ataque emocional específicamente dirigido con la intención de hacer daño', + } }; diff --git a/src/pages/FlagCommentPage.js b/src/pages/FlagCommentPage.js index f6e0193e261f..a15ede7b93e6 100644 --- a/src/pages/FlagCommentPage.js +++ b/src/pages/FlagCommentPage.js @@ -18,39 +18,39 @@ function FlagCommentPage(props) { const severities = [ { severity: 'spam', - name: 'Spam', + name: props.translate('moderation.spam'), icon: Expensicons.FlagLevelOne, - description: 'Unsolicited off-topic promotion', + description: props.translate('moderation.spamDescription'), }, { severity: 'inconsiderate', - name: 'Inconsiderate', + name: props.translate('moderation.inconsiderate'), icon: Expensicons.FlagLevelOne, - description: 'Phrased insultingly or disrespectfully, with questionable intentions', + description: props.translate('moderation.inconsiderateDescription'), }, { severity: 'intimidation', - name: 'Intimidation', + name: props.translate('moderation.intimidation'), icon: Expensicons.FlagLevelTwo, - description: 'Aggressively pursuing an agenda over valid objections', + description: props.translate('moderation.intimidationDescription'), }, { severity: 'bullying', - name: 'Bullying', + name: props.translate('moderation.bullying'), icon: Expensicons.FlagLevelTwo, - description: 'Targeting an individual to obtain obedience', + description: props.translate('moderation.bullyingDescription'), }, { severity: 'harassment', - name: 'Harassment', + name: props.translate('moderation.harassment'), icon: Expensicons.FlagLevelThree, - description: 'Racist, misogynistic, or other broadly discriminatory behavior', + description: props.translate('moderation.harassmentDescription'), }, { severity: 'assault', - name: 'Assault', + name: props.translate('moderation.assault'), icon: Expensicons.FlagLevelThree, - description: 'Specifically targeted emotional attack with the intention of harm', + description: props.translate('moderation.assaultDescription'), }, ]; @@ -68,9 +68,6 @@ function FlagCommentPage(props) { description={item.description} onPress={() => flagComment(item.severity)} wrapperStyle={[styles.borderBottom]} - // furtherDetails={this.props.translate('flags.sendAnonymousWarning')} - // furtherDetailsIcon={Expensicons.CircleFlag} - // furtherDetailsIconFill={colors.yellow} />) ) @@ -79,7 +76,7 @@ function FlagCommentPage(props) { {({safeAreaPaddingBottomStyle}) => ( <> Navigation.dismissModal(true)} /> - {'Description of stuff lorem ipsum Description of stuff lorem ipsum Description of stuff lorem ipsum Description of stuff lorem ipsum Description of stuff lorem ipsum Description of stuff lorem ipsum Description of stuff lorem ipsum '} + {props.translate('moderation.flagDescription')} - {'Choose a reason below:'} + {props.translate('moderation.chooseAReason')} {severityMenuItems} From 15e4aef1d2bda11310f84b09517bce6e8a3f59cf Mon Sep 17 00:00:00 2001 From: Daniel Gale-Rosen Date: Fri, 26 May 2023 13:23:47 -0400 Subject: [PATCH 383/751] call the flagComment method --- src/pages/FlagCommentPage.js | 54 ++++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/src/pages/FlagCommentPage.js b/src/pages/FlagCommentPage.js index a15ede7b93e6..d987c403e4e3 100644 --- a/src/pages/FlagCommentPage.js +++ b/src/pages/FlagCommentPage.js @@ -1,7 +1,12 @@ -import React, {useMemo} from 'react'; +import React from 'react'; import _ from 'underscore'; import {View, ScrollView} from 'react-native'; +import PropTypes from 'prop-types'; +import {withOnyx} from 'react-native-onyx'; +import reportActionPropTypes from './home/report/reportActionPropTypes'; import withLocalize, {withLocalizePropTypes} from '../components/withLocalize'; +import compose from '../libs/compose'; +import ONYXKEYS from '../ONYXKEYS'; import ScreenWrapper from '../components/ScreenWrapper'; import HeaderWithCloseButton from '../components/HeaderWithCloseButton'; import styles from '../styles/styles'; @@ -9,12 +14,44 @@ import Navigation from '../libs/Navigation/Navigation'; import Text from '../components/Text'; import * as Expensicons from '../components/Icon/Expensicons'; import MenuItem from '../components/MenuItem'; +import * as Report from '../libs/actions/Report'; const propTypes = { + /** Array of report actions for this report */ + reportActions: PropTypes.shape(reportActionPropTypes), + + /** Route params */ + route: PropTypes.shape({ + params: PropTypes.shape({ + /** Report ID passed via route r/:reportID/:reportActionID */ + reportID: PropTypes.string, + + /** ReportActionID passed via route r/:reportID/:reportActionID */ + reportActionID: PropTypes.string, + }), + }).isRequired, + ...withLocalizePropTypes, }; +const defaultProps = { + reportActions: {}, +} + +/** + * Get the reportID for the associated chatReport + * + * @param {Object} route + * @param {Object} route.params + * @param {String} route.params.reportID + * @returns {String} + */ +function getReportID(route) { + return route.params.reportID.toString(); +} + function FlagCommentPage(props) { + const reportAction = props.reportActions[`${props.route.params.reportActionID.toString()}`]; const severities = [ { severity: 'spam', @@ -55,9 +92,7 @@ function FlagCommentPage(props) { ]; const flagComment = (severity) => { - console.log(severity); - console.log(props.route.params.reportActionID); - console.log(props.route.params.reportID); + Report.flagComment(props.route.params.reportID, reportAction, severity); }; const severityMenuItems = _.map(severities, (item, index) => ( `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${getReportID(route)}`, + canEvict: false, + }, + }), +)(FlagCommentPage); From 48f1be5f9b53aa2ab490c637eaf1337191148d57 Mon Sep 17 00:00:00 2001 From: Daniel Gale-Rosen Date: Fri, 26 May 2023 13:24:54 -0400 Subject: [PATCH 384/751] style and prettier --- src/languages/en.js | 5 +++-- src/languages/es.js | 5 +++-- .../AppNavigator/ModalStackNavigators.js | 4 ++-- src/pages/FlagCommentPage.js | 21 +++++++------------ .../report/ContextMenu/ContextMenuActions.js | 13 ++++++------ 5 files changed, 23 insertions(+), 25 deletions(-) diff --git a/src/languages/en.js b/src/languages/en.js index 5493eae81e2e..93db740ee6a5 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -1402,7 +1402,8 @@ export default { copied: 'Copied!', }, moderation: { - flagDescription: 'All flagged messages will be sent to a moderator for review. If a message is flagged at a level above Spam or Inconsiderate, it will immediately be hidden. Users may, however, choose to reveal the message while it is being reviewed if they choose. Dependent on the decision of the moderator, the message may or may not be permanently hidden or deleted, and the sender may be banned from posting temporarily or permanently.', + flagDescription: + 'All flagged messages will be sent to a moderator for review. If a message is flagged at a level above Spam or Inconsiderate, it will immediately be hidden. Users may, however, choose to reveal the message while it is being reviewed if they choose. Dependent on the decision of the moderator, the message may or may not be permanently hidden or deleted, and the sender may be banned from posting temporarily or permanently.', chooseAReason: 'Choose a reason below:', spam: 'Spam', spamDescription: 'Unsolicited off-topic promotion', @@ -1416,5 +1417,5 @@ export default { harassmentDescription: 'Racist, misogynistic, or other broadly discriminatory behavior', assault: 'Assault', assaultDescription: 'Specifically targeted emotional attack with the intention of harm', - } + }, }; diff --git a/src/languages/es.js b/src/languages/es.js index 381f534eaeab..87db94913051 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -1868,7 +1868,8 @@ export default { copied: '¡Copiado!', }, moderation: { - flagDescription: 'Todos los mensajes marcados se enviarán a un moderador para su revisión. Si un mensaje se marca en un nivel superior a Spam o Desconsiderado, se ocultará de inmediato. Sin embargo, los usuarios pueden optar por revelar el mensaje mientras se revisa si así lo desean. Dependiendo de la decisión del moderador, el mensaje puede ocultarse o eliminarse permanentemente o no, y el remitente puede tener prohibido enviar mensajes de forma temporal o permanente.', + flagDescription: + 'Todos los mensajes marcados se enviarán a un moderador para su revisión. Si un mensaje se marca en un nivel superior a Spam o Desconsiderado, se ocultará de inmediato. Sin embargo, los usuarios pueden optar por revelar el mensaje mientras se revisa si así lo desean. Dependiendo de la decisión del moderador, el mensaje puede ocultarse o eliminarse permanentemente o no, y el remitente puede tener prohibido enviar mensajes de forma temporal o permanente.', chooseAReason: 'Elige un motivo de abajo', spam: 'Spam', spamDescription: 'Promoción fuera de tema no solicitada', @@ -1882,5 +1883,5 @@ export default { harassmentDescription: 'Comportamiento racista, misógino u otro comportamiento ampliamente discriminatorio', assault: 'Agresion', assaultDescription: 'Ataque emocional específicamente dirigido con la intención de hacer daño', - } + }, }; diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js index c76295b98a77..966d40f9f7d0 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js @@ -703,13 +703,13 @@ const YearPickerStackNavigator = createModalStackNavigator([ ]); const FlagCommentStackNavigator = createModalStackNavigator([ - { + { getComponent: () => { const FlagCommentPage = require('../../../pages/FlagCommentPage').default; return FlagCommentPage; }, name: 'FlagComment_Root', - } + }, ]); export { diff --git a/src/pages/FlagCommentPage.js b/src/pages/FlagCommentPage.js index d987c403e4e3..555b6aa6e205 100644 --- a/src/pages/FlagCommentPage.js +++ b/src/pages/FlagCommentPage.js @@ -30,13 +30,13 @@ const propTypes = { reportActionID: PropTypes.string, }), }).isRequired, - + ...withLocalizePropTypes, }; const defaultProps = { reportActions: {}, -} +}; /** * Get the reportID for the associated chatReport @@ -95,7 +95,8 @@ function FlagCommentPage(props) { Report.flagComment(props.route.params.reportID, reportAction, severity); }; - const severityMenuItems = _.map(severities, (item, index) => ( ( + flagComment(item.severity)} wrapperStyle={[styles.borderBottom]} - />) - ) + /> + )); return ( @@ -120,20 +121,15 @@ function FlagCommentPage(props) { > - - {props.translate('moderation.flagDescription')} - + {props.translate('moderation.flagDescription')} - - {props.translate('moderation.chooseAReason')} - + {props.translate('moderation.chooseAReason')} {severityMenuItems} )} - ); } @@ -150,4 +146,3 @@ export default compose( }, }), )(FlagCommentPage); - diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index 5dd598342c83..d7af24b180ab 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -270,16 +270,17 @@ export default [ textTranslateKey: 'reportActionContextMenu.flagAsOffensive', icon: Expensicons.Flag, shouldShow: (type, reportAction, isArchivedRoom, betas, menuTarget, isChronosReport, reportID) => - type === CONTEXT_MENU_TYPES.REPORT_ACTION && ReportUtils.canFlagReportAction(reportAction, reportID) && !isArchivedRoom && !isChronosReport && !ReportUtils.isConciergeChatReport(reportID), + type === CONTEXT_MENU_TYPES.REPORT_ACTION && + ReportUtils.canFlagReportAction(reportAction, reportID) && + !isArchivedRoom && + !isChronosReport && + !ReportUtils.isConciergeChatReport(reportID), onPress: (closePopover, {reportID, reportAction}) => { if (closePopover) { - hideContextMenu( - false, - () => Navigation.navigate(ROUTES.getFlagCommentRoute(reportID, reportAction.reportActionID)) - ); + hideContextMenu(false, () => Navigation.navigate(ROUTES.getFlagCommentRoute(reportID, reportAction.reportActionID))); } - Navigation.navigate(ROUTES.getFlagCommentRoute(reportID, reportAction.reportActionID)) + Navigation.navigate(ROUTES.getFlagCommentRoute(reportID, reportAction.reportActionID)); }, getDescription: () => {}, }, From 41525184d817d945d5d29bf5264f254b3dad9fe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Ch=C3=A1vez?= Date: Fri, 26 May 2023 11:42:10 -0600 Subject: [PATCH 385/751] sign out and redirect to sign in when anonymous user adds a reaction --- src/components/Reactions/AddReactionBubble.js | 26 ++++++++++++++- .../Reactions/MiniQuickEmojiReactions.js | 33 +++++++++++++++++-- .../BaseQuickEmojiReactions.js | 18 +++++++++- 3 files changed, 73 insertions(+), 4 deletions(-) diff --git a/src/components/Reactions/AddReactionBubble.js b/src/components/Reactions/AddReactionBubble.js index 992156488a72..a1167b0107f8 100644 --- a/src/components/Reactions/AddReactionBubble.js +++ b/src/components/Reactions/AddReactionBubble.js @@ -1,6 +1,7 @@ import React, {useRef} from 'react'; import {Pressable, View} from 'react-native'; import PropTypes from 'prop-types'; +import {withOnyx} from 'react-native-onyx'; import Tooltip from '../Tooltip'; import styles from '../../styles/styles'; import * as StyleUtils from '../../styles/StyleUtils'; @@ -11,6 +12,10 @@ import getButtonState from '../../libs/getButtonState'; import * as EmojiPickerAction from '../../libs/actions/EmojiPickerAction'; import variables from '../../styles/variables'; import withLocalize, {withLocalizePropTypes} from '../withLocalize'; +import compose from '../../libs/compose'; +import ONYXKEYS from '../../ONYXKEYS'; +import * as SessionUtils from '../../libs/SessionUtils'; +import * as Session from '../../libs/actions/Session'; const propTypes = { /** Whether it is for context menu so we can modify its style */ @@ -33,10 +38,17 @@ const propTypes = { */ onSelectEmoji: PropTypes.func.isRequired, + /** Session info for the currently logged in user. */ + session: PropTypes.shape({ + /** Currently logged in user email */ + email: PropTypes.string, + }), + ...withLocalizePropTypes, }; const defaultProps = { + session: {}, isContextMenu: false, onWillShowPicker: () => {}, onPressOpenPicker: undefined, @@ -46,6 +58,11 @@ const AddReactionBubble = (props) => { const ref = useRef(); const onPress = () => { + if (SessionUtils.isAnonymousUser(props.session.authTokenType)) { + Session.signOutAndRedirectToSignIn(); + return; + } + const openPicker = (refParam, anchorOrigin) => { EmojiPickerAction.showEmojiPicker( () => {}, @@ -99,4 +116,11 @@ AddReactionBubble.propTypes = propTypes; AddReactionBubble.defaultProps = defaultProps; AddReactionBubble.displayName = 'AddReactionBubble'; -export default withLocalize(AddReactionBubble); +export default compose( + withLocalize, + withOnyx({ + session: { + key: ONYXKEYS.SESSION, + }, + }) +)(AddReactionBubble); \ No newline at end of file diff --git a/src/components/Reactions/MiniQuickEmojiReactions.js b/src/components/Reactions/MiniQuickEmojiReactions.js index 66f39e32fc67..1418c58c7f0c 100644 --- a/src/components/Reactions/MiniQuickEmojiReactions.js +++ b/src/components/Reactions/MiniQuickEmojiReactions.js @@ -17,6 +17,8 @@ import withLocalize, {withLocalizePropTypes} from '../withLocalize'; import compose from '../../libs/compose'; import ONYXKEYS from '../../ONYXKEYS'; import * as EmojiUtils from '../../libs/EmojiUtils'; +import * as SessionUtils from '../../libs/SessionUtils'; +import * as Session from '../../libs/actions/Session'; const propTypes = { ...baseQuickEmojiReactionsPropTypes, @@ -29,9 +31,16 @@ const propTypes = { ...withLocalizePropTypes, preferredSkinTone: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), + + /** Session info for the currently logged in user. */ + session: PropTypes.shape({ + /** Currently logged in user email */ + email: PropTypes.string, + }), }; const defaultProps = { + session: {}, onEmojiPickerClosed: () => {}, preferredSkinTone: CONST.EMOJI_DEFAULT_SKIN_TONE, }; @@ -48,6 +57,11 @@ const MiniQuickEmojiReactions = (props) => { const ref = useRef(); const openEmojiPicker = () => { + if (SessionUtils.isAnonymousUser(props.session.authTokenType)) { + Session.signOutAndRedirectToSignIn(); + return; + } + props.onPressOpenPicker(); EmojiPickerAction.showEmojiPicker( props.onEmojiPickerClosed, @@ -65,14 +79,26 @@ const MiniQuickEmojiReactions = (props) => { key={emoji.name} isDelayButtonStateComplete={false} tooltipText={`:${emoji.name}:`} - onPress={() => props.onEmojiSelected(emoji)} + onPress={() => { + if (SessionUtils.isAnonymousUser(props.session.authTokenType)) { + Session.signOutAndRedirectToSignIn(); + } else { + props.onEmojiSelected(emoji); + } + }} > {EmojiUtils.getPreferredEmojiCode(emoji, props.preferredSkinTone)} ))} { + if (SessionUtils.isAnonymousUser(props.session.authTokenType)) { + Session.signOutAndRedirectToSignIn(); + } else { + openEmojiPicker(); + } + }} isDelayButtonStateComplete={false} tooltipText={props.translate('emojiReactions.addReactionTooltip')} > @@ -94,6 +120,9 @@ MiniQuickEmojiReactions.defaultProps = defaultProps; export default compose( withLocalize, withOnyx({ + session: { + key: ONYXKEYS.SESSION, + }, preferredSkinTone: { key: ONYXKEYS.PREFERRED_EMOJI_SKIN_TONE, }, diff --git a/src/components/Reactions/QuickEmojiReactions/BaseQuickEmojiReactions.js b/src/components/Reactions/QuickEmojiReactions/BaseQuickEmojiReactions.js index 12feef57ebfc..9fabaad0a812 100644 --- a/src/components/Reactions/QuickEmojiReactions/BaseQuickEmojiReactions.js +++ b/src/components/Reactions/QuickEmojiReactions/BaseQuickEmojiReactions.js @@ -10,6 +10,8 @@ import styles from '../../../styles/styles'; import ONYXKEYS from '../../../ONYXKEYS'; import Tooltip from '../../Tooltip'; import * as EmojiUtils from '../../../libs/EmojiUtils'; +import * as SessionUtils from '../../../libs/SessionUtils'; +import * as Session from "../../../libs/actions/Session"; const baseQuickEmojiReactionsPropTypes = { /** @@ -28,9 +30,16 @@ const baseQuickEmojiReactionsPropTypes = { * to actually open the emoji picker. */ onPressOpenPicker: PropTypes.func, + + /** Session info for the currently logged in user. */ + session: PropTypes.shape({ + /** Currently logged in user email */ + email: PropTypes.string, + }), }; const baseQuickEmojiReactionsDefaultProps = { + session: {}, onWillShowPicker: () => {}, onPressOpenPicker: () => {}, }; @@ -57,7 +66,11 @@ const BaseQuickEmojiReactions = (props) => ( emojiCodes={[EmojiUtils.getPreferredEmojiCode(emoji, props.preferredSkinTone)]} isContextMenu onPress={() => { - props.onEmojiSelected(emoji); + if (SessionUtils.isAnonymousUser(props.session.authTokenType)) { + Session.signOutAndRedirectToSignIn(); + } else { + props.onEmojiSelected(emoji); + } }} /> @@ -76,6 +89,9 @@ BaseQuickEmojiReactions.displayName = 'BaseQuickEmojiReactions'; BaseQuickEmojiReactions.propTypes = propTypes; BaseQuickEmojiReactions.defaultProps = defaultProps; export default withOnyx({ + session: { + key: ONYXKEYS.SESSION, + }, preferredSkinTone: { key: ONYXKEYS.PREFERRED_EMOJI_SKIN_TONE, }, From 6709e2a7f173bccc3f4597b3b68b009859292220 Mon Sep 17 00:00:00 2001 From: Daniel Gale-Rosen Date: Fri, 26 May 2023 13:45:50 -0400 Subject: [PATCH 386/751] update to work with new backend logic re: moderationDecisions object --- src/languages/es.js | 6 +++--- src/libs/actions/Report.js | 26 +++++++++++++------------- src/pages/FlagCommentPage.js | 1 + 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/languages/es.js b/src/languages/es.js index 87db94913051..697c2819902b 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -1870,7 +1870,7 @@ export default { moderation: { flagDescription: 'Todos los mensajes marcados se enviarán a un moderador para su revisión. Si un mensaje se marca en un nivel superior a Spam o Desconsiderado, se ocultará de inmediato. Sin embargo, los usuarios pueden optar por revelar el mensaje mientras se revisa si así lo desean. Dependiendo de la decisión del moderador, el mensaje puede ocultarse o eliminarse permanentemente o no, y el remitente puede tener prohibido enviar mensajes de forma temporal o permanente.', - chooseAReason: 'Elige un motivo de abajo', + chooseAReason: 'Elige un motivo de abajo:', spam: 'Spam', spamDescription: 'Promoción fuera de tema no solicitada', inconsiderate: 'Desconsiderado', @@ -1878,9 +1878,9 @@ export default { intimidation: 'Intimidación', intimidationDescription: 'Persigue agresivamente una agenda sobre objeciones válidas', bullying: 'Bullying', - bullyingDescription: 'Apunta a un individuo para obtener obediencia.', + bullyingDescription: 'Apunta a un individuo para obtener obediencia', harassment: 'Acoso', - harassmentDescription: 'Comportamiento racista, misógino u otro comportamiento ampliamente discriminatorio', + harassmentDescription: 'Comportamiento racista, misógino u otro comportamiento discriminatorio', assault: 'Agresion', assaultDescription: 'Ataque emocional específicamente dirigido con la intención de hacer daño', }, diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index e7d37ecea837..ee5fe2f0f466 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -1685,30 +1685,30 @@ function leaveRoom(reportID) { * @param {String} severity */ function flagComment(reportID, reportAction, severity) { - let newDecision; + const message = reportAction.message[0]; + let updatedDecision; if (severity === CONST.MODERATION.FLAG_SEVERITY_SPAM || severity === CONST.MODERATION.FLAG_SEVERITY_INCONSIDERATE) { - newDecision = { - decision: CONST.MODERATION.MODERATOR_DECISION_PENDING, - }; + if (_.isEmpty(message.moderationDecisions) || message.moderationDecisions[0].decision !== CONST.MODERATOR_DECISION_PENDING_HIDE) { + updatedDecision = [{ + decision: CONST.MODERATION.MODERATOR_DECISION_PENDING, + }]; + } } else { - newDecision = { + updatedDecision = [{ decision: CONST.MODERATION.MODERATOR_DECISION_PENDING_HIDE, - }; + }]; } - const message = reportAction.message[0]; const reportActionID = reportAction.reportActionID; - const updatedDecisions = [...(message.moderationDecisions || []), newDecision]; - const updatedMessage = { ...message, - moderationDecisions: updatedDecisions, + moderationDecisions: updatedDecision, }; const optimisticData = [ { - onyxMethod: CONST.ONYX.METHOD.MERGE, + onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, value: { [reportActionID]: { @@ -1721,7 +1721,7 @@ function flagComment(reportID, reportAction, severity) { const failureData = [ { - onyxMethod: CONST.ONYX.METHOD.MERGE, + onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, value: { [reportActionID]: { @@ -1734,7 +1734,7 @@ function flagComment(reportID, reportAction, severity) { const successData = [ { - onyxMethod: CONST.ONYX.METHOD.MERGE, + onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, value: { [reportActionID]: { diff --git a/src/pages/FlagCommentPage.js b/src/pages/FlagCommentPage.js index 555b6aa6e205..b94dad99639f 100644 --- a/src/pages/FlagCommentPage.js +++ b/src/pages/FlagCommentPage.js @@ -93,6 +93,7 @@ function FlagCommentPage(props) { const flagComment = (severity) => { Report.flagComment(props.route.params.reportID, reportAction, severity); + Navigation.dismissModal(true) }; const severityMenuItems = _.map(severities, (item, index) => ( From b3454c08099979407ef2e32477affdd65cd961e3 Mon Sep 17 00:00:00 2001 From: Jakub Trzebiatowski Date: Thu, 18 May 2023 18:53:08 +0200 Subject: [PATCH 387/751] Pass `props.windowHeight` to `getBaseNavigationModalCardStyles` ...to work around Safari CSS issues. --- src/libs/Navigation/AppNavigator/AuthScreens.js | 7 +++++-- .../getBaseNavigationModalCardStyles.js | 2 +- .../getNavigationModalCardStyles/index.website.js | 12 +++++++----- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.js b/src/libs/Navigation/AppNavigator/AuthScreens.js index 0e523002a939..63e2cb9c4972 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.js +++ b/src/libs/Navigation/AppNavigator/AuthScreens.js @@ -157,7 +157,7 @@ class AuthScreens extends React.Component { } shouldComponentUpdate(nextProps) { - return nextProps.isSmallScreenWidth !== this.props.isSmallScreenWidth; + return nextProps.windowHeight !== this.props.windowHeight || nextProps.isSmallScreenWidth !== this.props.isSmallScreenWidth; } componentWillUnmount() { @@ -184,7 +184,10 @@ class AuthScreens extends React.Component { }; const modalScreenOptions = { ...commonModalScreenOptions, - cardStyle: getNavigationModalCardStyle(this.props.isSmallScreenWidth), + cardStyle: getNavigationModalCardStyle({ + windowHeight: this.props.windowHeight, + isSmallScreenWidth: this.props.isSmallScreenWidth, + }), cardStyleInterpolator: (props) => modalCardStyleInterpolator(this.props.isSmallScreenWidth, false, props), cardOverlayEnabled: true, diff --git a/src/styles/getNavigationModalCardStyles/getBaseNavigationModalCardStyles.js b/src/styles/getNavigationModalCardStyles/getBaseNavigationModalCardStyles.js index 51691d801956..bddb639655a0 100644 --- a/src/styles/getNavigationModalCardStyles/getBaseNavigationModalCardStyles.js +++ b/src/styles/getNavigationModalCardStyles/getBaseNavigationModalCardStyles.js @@ -1,6 +1,6 @@ import variables from '../variables'; -export default (isSmallScreenWidth) => ({ +export default ({isSmallScreenWidth}) => ({ position: 'absolute', top: 0, right: 0, diff --git a/src/styles/getNavigationModalCardStyles/index.website.js b/src/styles/getNavigationModalCardStyles/index.website.js index 1b55c6891266..8f76cf8d17d5 100644 --- a/src/styles/getNavigationModalCardStyles/index.website.js +++ b/src/styles/getNavigationModalCardStyles/index.website.js @@ -1,9 +1,11 @@ import getBaseNavigationModalCardStyles from './getBaseNavigationModalCardStyles'; -export default (isSmallScreenWidth) => ({ - ...getBaseNavigationModalCardStyles(isSmallScreenWidth), +export default ({windowHeight, isSmallScreenWidth}) => ({ + ...getBaseNavigationModalCardStyles({isSmallScreenWidth}), - // This makes the modal card take up the full height of the screen on Desktop Safari and iOS Safari - // https://github.com/Expensify/App/pull/12509/files#r1018107162 - height: 'calc(100vh - 100%)', + // This height is passed from JavaScript, instead of using CSS expressions like "100%" or "100vh", to work around + // Safari issues: + // https://github.com/Expensify/App/issues/12005 + // https://github.com/Expensify/App/issues/17824 + height: `${windowHeight}px`, }); From 3cf9de32d965fd392675fcf580a128e18bbe765b Mon Sep 17 00:00:00 2001 From: tienifr Date: Sat, 27 May 2023 01:29:15 +0700 Subject: [PATCH 388/751] share destination is required --- src/pages/tasks/NewTaskPage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/tasks/NewTaskPage.js b/src/pages/tasks/NewTaskPage.js index 3eb235c54a5c..7c09fd50d65c 100644 --- a/src/pages/tasks/NewTaskPage.js +++ b/src/pages/tasks/NewTaskPage.js @@ -105,7 +105,7 @@ const NewTaskPage = (props) => { // On submit, we want to call the createTask function and wait to validate // the response function onSubmit() { - if (!props.task.title || (!OptionsListUtils.isCurrentUser({login: props.task.assignee}) && !props.task.shareDestination)) { + if (!props.task.title || !props.task.shareDestination) { setSubmitError(true); return; } From 7fd30eee91f0d03dfbe244284e61e0f2270f8fc7 Mon Sep 17 00:00:00 2001 From: tienifr Date: Sat, 27 May 2023 01:40:11 +0700 Subject: [PATCH 389/751] fix lint --- src/pages/tasks/NewTaskPage.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/tasks/NewTaskPage.js b/src/pages/tasks/NewTaskPage.js index 7c09fd50d65c..d6e13218423d 100644 --- a/src/pages/tasks/NewTaskPage.js +++ b/src/pages/tasks/NewTaskPage.js @@ -14,7 +14,6 @@ import Permissions from '../../libs/Permissions'; import ROUTES from '../../ROUTES'; import TaskSelectorLink from '../../components/TaskSelectorLink'; import reportPropTypes from '../reportPropTypes'; -import * as OptionsListUtils from '../../libs/OptionsListUtils'; import * as TaskUtils from '../../libs/actions/Task'; import FormAlertWithSubmitButton from '../../components/FormAlertWithSubmitButton'; From ef9189a8180d1118361b1d1c57bcdeb39ff502e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Ch=C3=A1vez?= Date: Fri, 26 May 2023 13:08:35 -0600 Subject: [PATCH 390/751] add checkIfActionIsAllowed function --- src/components/Reactions/AddReactionBubble.js | 8 +------ .../Reactions/MiniQuickEmojiReactions.js | 21 ++----------------- .../BaseQuickEmojiReactions.js | 9 +------- .../BaseVideoChatButtonAndMenu.js | 11 ++-------- src/libs/actions/Session/index.js | 17 +++++++++++++++ src/pages/ReportDetailsPage.js | 9 +------- src/pages/home/HeaderView.js | 9 +------- src/pages/home/sidebar/SidebarLinks.js | 18 ++++++---------- 8 files changed, 31 insertions(+), 71 deletions(-) diff --git a/src/components/Reactions/AddReactionBubble.js b/src/components/Reactions/AddReactionBubble.js index a1167b0107f8..208a740da1b5 100644 --- a/src/components/Reactions/AddReactionBubble.js +++ b/src/components/Reactions/AddReactionBubble.js @@ -14,7 +14,6 @@ import variables from '../../styles/variables'; import withLocalize, {withLocalizePropTypes} from '../withLocalize'; import compose from '../../libs/compose'; import ONYXKEYS from '../../ONYXKEYS'; -import * as SessionUtils from '../../libs/SessionUtils'; import * as Session from '../../libs/actions/Session'; const propTypes = { @@ -58,11 +57,6 @@ const AddReactionBubble = (props) => { const ref = useRef(); const onPress = () => { - if (SessionUtils.isAnonymousUser(props.session.authTokenType)) { - Session.signOutAndRedirectToSignIn(); - return; - } - const openPicker = (refParam, anchorOrigin) => { EmojiPickerAction.showEmojiPicker( () => {}, @@ -87,7 +81,7 @@ const AddReactionBubble = (props) => { [styles.emojiReactionBubble, styles.userSelectNone, StyleUtils.getEmojiReactionBubbleStyle(hovered || pressed, false, props.isContextMenu)]} - onPress={onPress} + onPress={Session.checkIfActionIsAllowed(props.session.authTokenType, onPress)} // Prevent text input blur when Add reaction is clicked onMouseDown={(e) => e.preventDefault()} > diff --git a/src/components/Reactions/MiniQuickEmojiReactions.js b/src/components/Reactions/MiniQuickEmojiReactions.js index 1418c58c7f0c..1154ea22e9e4 100644 --- a/src/components/Reactions/MiniQuickEmojiReactions.js +++ b/src/components/Reactions/MiniQuickEmojiReactions.js @@ -57,11 +57,6 @@ const MiniQuickEmojiReactions = (props) => { const ref = useRef(); const openEmojiPicker = () => { - if (SessionUtils.isAnonymousUser(props.session.authTokenType)) { - Session.signOutAndRedirectToSignIn(); - return; - } - props.onPressOpenPicker(); EmojiPickerAction.showEmojiPicker( props.onEmojiPickerClosed, @@ -79,26 +74,14 @@ const MiniQuickEmojiReactions = (props) => { key={emoji.name} isDelayButtonStateComplete={false} tooltipText={`:${emoji.name}:`} - onPress={() => { - if (SessionUtils.isAnonymousUser(props.session.authTokenType)) { - Session.signOutAndRedirectToSignIn(); - } else { - props.onEmojiSelected(emoji); - } - }} + onPress={Session.checkIfActionIsAllowed(props.session.authTokenType, () => props.onEmojiSelected(emoji))} > {EmojiUtils.getPreferredEmojiCode(emoji, props.preferredSkinTone)} ))} { - if (SessionUtils.isAnonymousUser(props.session.authTokenType)) { - Session.signOutAndRedirectToSignIn(); - } else { - openEmojiPicker(); - } - }} + onPress={Session.checkIfActionIsAllowed(props.session.authTokenType, openEmojiPicker)} isDelayButtonStateComplete={false} tooltipText={props.translate('emojiReactions.addReactionTooltip')} > diff --git a/src/components/Reactions/QuickEmojiReactions/BaseQuickEmojiReactions.js b/src/components/Reactions/QuickEmojiReactions/BaseQuickEmojiReactions.js index 9fabaad0a812..298a12efa273 100644 --- a/src/components/Reactions/QuickEmojiReactions/BaseQuickEmojiReactions.js +++ b/src/components/Reactions/QuickEmojiReactions/BaseQuickEmojiReactions.js @@ -10,7 +10,6 @@ import styles from '../../../styles/styles'; import ONYXKEYS from '../../../ONYXKEYS'; import Tooltip from '../../Tooltip'; import * as EmojiUtils from '../../../libs/EmojiUtils'; -import * as SessionUtils from '../../../libs/SessionUtils'; import * as Session from "../../../libs/actions/Session"; const baseQuickEmojiReactionsPropTypes = { @@ -65,13 +64,7 @@ const BaseQuickEmojiReactions = (props) => ( { - if (SessionUtils.isAnonymousUser(props.session.authTokenType)) { - Session.signOutAndRedirectToSignIn(); - } else { - props.onEmojiSelected(emoji); - } - }} + onPress={Session.checkIfActionIsAllowed(props.session.authTokenType, () => props.onEmojiSelected(emoji))} /> diff --git a/src/components/VideoChatButtonAndMenu/BaseVideoChatButtonAndMenu.js b/src/components/VideoChatButtonAndMenu/BaseVideoChatButtonAndMenu.js index e7574b756721..fe240a748847 100755 --- a/src/components/VideoChatButtonAndMenu/BaseVideoChatButtonAndMenu.js +++ b/src/components/VideoChatButtonAndMenu/BaseVideoChatButtonAndMenu.js @@ -17,7 +17,6 @@ import withLocalize, {withLocalizePropTypes} from '../withLocalize'; import compose from '../../libs/compose'; import Tooltip from '../Tooltip'; import {propTypes as videoChatButtonAndMenuPropTypes, defaultProps} from './videoChatButtonAndMenuPropTypes'; -import * as SessionUtils from '../../libs/SessionUtils'; import * as Session from '../../libs/actions/Session'; import ONYXKEYS from '../../ONYXKEYS'; @@ -112,23 +111,17 @@ class BaseVideoChatButtonAndMenu extends Component { (this.videoChatButton = el)} - onPress={() => { + onPress={Session.checkIfActionIsAllowed(this.props.session.authTokenType, () => { // Drop focus to avoid blue focus ring. this.videoChatButton.blur(); - // If user is anonymous, show the sign in modal - if (SessionUtils.isAnonymousUser(this.props.session.authTokenType)) { - Session.signOutAndRedirectToSignIn(); - return; - } - // If this is the Concierge chat, we'll open the modal for requesting a setup call instead if (this.props.isConcierge && this.props.guideCalendarLink) { Linking.openURL(this.props.guideCalendarLink); return; } this.setMenuVisibility(true); - }} + })} style={[styles.touchableButtonImage]} > { + if (SessionUtils.isAnonymousUser(authTokenType)) { + return signOutAndRedirectToSignIn(); + } + return callback(); + } +} + /** * Resend the validation link to the user that is validating their account * @@ -887,6 +903,7 @@ function validateTwoFactorAuth(twoFactorAuthCode) { export { beginSignIn, + checkIfActionIsAllowed, updatePasswordAndSignin, signIn, signInWithValidateCode, diff --git a/src/pages/ReportDetailsPage.js b/src/pages/ReportDetailsPage.js index e88a8a562318..8d5daba07a52 100644 --- a/src/pages/ReportDetailsPage.js +++ b/src/pages/ReportDetailsPage.js @@ -18,7 +18,6 @@ import * as ReportUtils from '../libs/ReportUtils'; import * as PolicyUtils from '../libs/PolicyUtils'; import * as Report from '../libs/actions/Report'; import * as Session from '../libs/actions/Session'; -import * as SessionUtils from '../libs/SessionUtils'; import participantPropTypes from '../components/participantPropTypes'; import * as Expensicons from '../components/Icon/Expensicons'; import ROUTES from '../ROUTES'; @@ -189,13 +188,7 @@ class ReportDetailsPage extends Component { title={this.props.translate(item.translationKey)} subtitle={item.subtitle} icon={item.icon} - onPress={() => { - if (SessionUtils.isAnonymousUser(this.props.session.authTokenType)) { - Session.signOutAndRedirectToSignIn(); - } else { - item.action(); - } - }} + onPress={Session.checkIfActionIsAllowed(this.props.session.authTokenType, item.action)} shouldShowRightIcon brickRoadIndicator={brickRoadIndicator} /> diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index ac03c98c6db9..8b092bc03953 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -28,7 +28,6 @@ import ONYXKEYS from '../../ONYXKEYS'; import ThreeDotsMenu from '../../components/ThreeDotsMenu'; import * as Task from '../../libs/actions/Task'; import reportActionPropTypes from './report/reportActionPropTypes'; -import * as SessionUtils from '../../libs/SessionUtils'; import * as Session from '../../libs/actions/Session'; const propTypes = { @@ -199,13 +198,7 @@ const HeaderView = (props) => { )} { - if (SessionUtils.isAnonymousUser(props.session.authTokenType)) { - Session.signOutAndRedirectToSignIn(); - } else { - Report.togglePinnedState(props.report); - } - }} + onPress={Session.checkIfActionIsAllowed(props.session.authTokenType, () => Report.togglePinnedState(props.report))} style={[styles.touchableButtonImage]} > @@ -184,7 +178,7 @@ class SidebarLinks extends React.Component { Date: Fri, 26 May 2023 15:29:59 -0400 Subject: [PATCH 391/751] add constants for all severities --- src/CONST.js | 4 ++++ src/pages/FlagCommentPage.js | 13 +++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/CONST.js b/src/CONST.js index 182548b4d99e..8b315ebb1b40 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -2434,6 +2434,10 @@ const CONST = { MODERATOR_DECISION_PENDING_HIDE: 'pendingHide', FLAG_SEVERITY_SPAM: 'spam', FLAG_SEVERITY_INCONSIDERATE: 'inconsiderate', + FLAG_SEVERITY_INTIMIDATION: 'intimidation', + FLAG_SEVERITY_BULLYING: 'bullying', + FLAG_SEVERITY_HARASSMENT: 'harassment', + FLAG_SEVERITY_ASSAULT: 'assault', }, }; diff --git a/src/pages/FlagCommentPage.js b/src/pages/FlagCommentPage.js index b94dad99639f..2ad91e4c564b 100644 --- a/src/pages/FlagCommentPage.js +++ b/src/pages/FlagCommentPage.js @@ -15,6 +15,7 @@ import Text from '../components/Text'; import * as Expensicons from '../components/Icon/Expensicons'; import MenuItem from '../components/MenuItem'; import * as Report from '../libs/actions/Report'; +import CONST from '../CONST'; const propTypes = { /** Array of report actions for this report */ @@ -54,37 +55,37 @@ function FlagCommentPage(props) { const reportAction = props.reportActions[`${props.route.params.reportActionID.toString()}`]; const severities = [ { - severity: 'spam', + severity: CONST.MODERATION.FLAG_SEVERITY_SPAM, name: props.translate('moderation.spam'), icon: Expensicons.FlagLevelOne, description: props.translate('moderation.spamDescription'), }, { - severity: 'inconsiderate', + severity: CONST.MODERATION.FLAG_SEVERITY_INCONSIDERATE, name: props.translate('moderation.inconsiderate'), icon: Expensicons.FlagLevelOne, description: props.translate('moderation.inconsiderateDescription'), }, { - severity: 'intimidation', + severity: CONST.MODERATION.FLAG_SEVERITY_INTIMIDATION, name: props.translate('moderation.intimidation'), icon: Expensicons.FlagLevelTwo, description: props.translate('moderation.intimidationDescription'), }, { - severity: 'bullying', + severity: CONST.MODERATION.FLAG_SEVERITY_BULLYING, name: props.translate('moderation.bullying'), icon: Expensicons.FlagLevelTwo, description: props.translate('moderation.bullyingDescription'), }, { - severity: 'harassment', + severity: CONST.MODERATION.FLAG_SEVERITY_HARASSMENT, name: props.translate('moderation.harassment'), icon: Expensicons.FlagLevelThree, description: props.translate('moderation.harassmentDescription'), }, { - severity: 'assault', + severity: CONST.MODERATION.FLAG_SEVERITY_ASSAULT, name: props.translate('moderation.assault'), icon: Expensicons.FlagLevelThree, description: props.translate('moderation.assaultDescription'), From a020c4995c742ec641f796dd06c968aa969e0c52 Mon Sep 17 00:00:00 2001 From: Daniel Gale-Rosen Date: Fri, 26 May 2023 15:30:39 -0400 Subject: [PATCH 392/751] prettier one more time --- src/libs/actions/Report.js | 16 ++++++++++------ src/pages/FlagCommentPage.js | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index ee5fe2f0f466..e0d405fb1313 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -1689,14 +1689,18 @@ function flagComment(reportID, reportAction, severity) { let updatedDecision; if (severity === CONST.MODERATION.FLAG_SEVERITY_SPAM || severity === CONST.MODERATION.FLAG_SEVERITY_INCONSIDERATE) { if (_.isEmpty(message.moderationDecisions) || message.moderationDecisions[0].decision !== CONST.MODERATOR_DECISION_PENDING_HIDE) { - updatedDecision = [{ - decision: CONST.MODERATION.MODERATOR_DECISION_PENDING, - }]; + updatedDecision = [ + { + decision: CONST.MODERATION.MODERATOR_DECISION_PENDING, + }, + ]; } } else { - updatedDecision = [{ - decision: CONST.MODERATION.MODERATOR_DECISION_PENDING_HIDE, - }]; + updatedDecision = [ + { + decision: CONST.MODERATION.MODERATOR_DECISION_PENDING_HIDE, + }, + ]; } const reportActionID = reportAction.reportActionID; diff --git a/src/pages/FlagCommentPage.js b/src/pages/FlagCommentPage.js index 2ad91e4c564b..a8163409b68b 100644 --- a/src/pages/FlagCommentPage.js +++ b/src/pages/FlagCommentPage.js @@ -94,7 +94,7 @@ function FlagCommentPage(props) { const flagComment = (severity) => { Report.flagComment(props.route.params.reportID, reportAction, severity); - Navigation.dismissModal(true) + Navigation.dismissModal(true); }; const severityMenuItems = _.map(severities, (item, index) => ( From 863422a6507fa1e06f4030fa28dfe822d9efcead Mon Sep 17 00:00:00 2001 From: Daniel Gale-Rosen Date: Fri, 26 May 2023 15:41:55 -0400 Subject: [PATCH 393/751] dont allow flagging of whispers from concierge --- src/pages/home/report/ContextMenu/ContextMenuActions.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index d7af24b180ab..d7ca6a5c8370 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -274,7 +274,8 @@ export default [ ReportUtils.canFlagReportAction(reportAction, reportID) && !isArchivedRoom && !isChronosReport && - !ReportUtils.isConciergeChatReport(reportID), + !ReportUtils.isConciergeChatReport(reportID) && + reportAction.actorEmail !== CONST.EMAIL.CONCIERGE, onPress: (closePopover, {reportID, reportAction}) => { if (closePopover) { hideContextMenu(false, () => Navigation.navigate(ROUTES.getFlagCommentRoute(reportID, reportAction.reportActionID))); From 5dfbc6556a174729194d1032ea525f284dc4d8eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Ch=C3=A1vez?= Date: Fri, 26 May 2023 14:08:54 -0600 Subject: [PATCH 394/751] open last public room opened by an anonymous user --- src/ONYXKEYS.js | 3 +++ .../Reactions/MiniQuickEmojiReactions.js | 1 - src/libs/actions/Report.js | 8 +++++++ src/libs/actions/Session/index.js | 18 ++++++++++++-- src/pages/home/ReportScreen.js | 24 +++++++++++++++++++ .../BaseReportActionContextMenu.js | 2 +- src/pages/home/report/ReportActionItem.js | 2 +- src/pages/home/sidebar/SidebarLinks.js | 1 - .../FloatingActionButtonAndPopover.js | 2 +- 9 files changed, 54 insertions(+), 7 deletions(-) diff --git a/src/ONYXKEYS.js b/src/ONYXKEYS.js index 0bb57acb1122..8cbf4a726f95 100755 --- a/src/ONYXKEYS.js +++ b/src/ONYXKEYS.js @@ -226,4 +226,7 @@ export default { // A map of the user's security group IDs they belong to in specific domains MY_DOMAIN_SECURITY_GROUPS: 'myDomainSecurityGroups', + + // Report ID of the last report the user viewed as anonymous user + LAST_OPENED_PUBLIC_ROOM_ID: 'lastOpenedPublicRoomID', }; diff --git a/src/components/Reactions/MiniQuickEmojiReactions.js b/src/components/Reactions/MiniQuickEmojiReactions.js index 1154ea22e9e4..e2934aa2fcfe 100644 --- a/src/components/Reactions/MiniQuickEmojiReactions.js +++ b/src/components/Reactions/MiniQuickEmojiReactions.js @@ -17,7 +17,6 @@ import withLocalize, {withLocalizePropTypes} from '../withLocalize'; import compose from '../../libs/compose'; import ONYXKEYS from '../../ONYXKEYS'; import * as EmojiUtils from '../../libs/EmojiUtils'; -import * as SessionUtils from '../../libs/SessionUtils'; import * as Session from '../../libs/actions/Session'; const propTypes = { diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 1d00a38fdd3b..ac6f26992653 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -1705,6 +1705,13 @@ function leaveRoom(reportID) { navigateToConciergeChat(); } +/** + * @param {String} reportID + */ +function setLastOpenedPublicRoom(reportID) { + Onyx.set(ONYXKEYS.LAST_OPENED_PUBLIC_ROOM_ID, reportID); +} + export { addComment, addAttachment, @@ -1749,4 +1756,5 @@ export { hasAccountIDReacted, shouldShowReportActionNotification, leaveRoom, + setLastOpenedPublicRoom, }; diff --git a/src/libs/actions/Session/index.js b/src/libs/actions/Session/index.js index 59fdcec86dc0..463e20a503e8 100644 --- a/src/libs/actions/Session/index.js +++ b/src/libs/actions/Session/index.js @@ -1,6 +1,7 @@ import Onyx from 'react-native-onyx'; import _ from 'underscore'; import lodashGet from 'lodash/get'; +import {Linking} from 'react-native'; import ONYXKEYS from '../../../ONYXKEYS'; import redirectToSignIn from '../SignInRedirect'; import CONFIG from '../../../CONFIG'; @@ -21,6 +22,8 @@ import subscribeToReportCommentPushNotifications from '../../Notification/PushNo import ROUTES from '../../../ROUTES'; import * as ErrorUtils from '../../ErrorUtils'; import * as SessionUtils from '../../SessionUtils'; +import * as ReportUtils from '../../ReportUtils'; +import * as Report from "../Report"; let credentials = {}; Onyx.connect({ @@ -79,10 +82,21 @@ function signOut() { Timing.clearData(); } -function signOutAndRedirectToSignIn() { +/** + * @param {String} [authTokenType] The type of auth token to check + */ +function signOutAndRedirectToSignIn(authTokenType = '') { signOut(); redirectToSignIn(); Log.info('Redirecting to Sign In because signOut() was called'); + if (SessionUtils.isAnonymousUser(authTokenType)) { + Linking.getInitialURL().then((url) => { + const reportID = ReportUtils.getReportIDFromLink(url); + if (reportID) { + Report.setLastOpenedPublicRoom(reportID); + } + }); + } } /** @@ -94,7 +108,7 @@ function signOutAndRedirectToSignIn() { function checkIfActionIsAllowed(authTokenType, callback) { return () => { if (SessionUtils.isAnonymousUser(authTokenType)) { - return signOutAndRedirectToSignIn(); + return signOutAndRedirectToSignIn(authTokenType); } return callback(); } diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index 223606dc30c3..307f703321ac 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -41,6 +41,7 @@ import * as EmojiPickerAction from '../../libs/actions/EmojiPickerAction'; import TaskHeader from '../../components/TaskHeader'; import MoneyRequestHeader from '../../components/MoneyRequestHeader'; import * as ComposerActions from '../../libs/actions/Composer'; +import * as SessionUtils from '../../libs/SessionUtils'; const propTypes = { /** Navigation route context info provided by react navigation */ @@ -84,9 +85,17 @@ const propTypes = { /** The account manager report ID */ accountManagerReportID: PropTypes.string, + /** The report ID of the last opened public room as anonymous user */ + lastOpenedPublicRoomID: PropTypes.string, + /** All of the personal details for everyone */ personalDetails: PropTypes.objectOf(personalDetailsPropType), + /** Current user session */ + session: PropTypes.shape({ + authTokenType: PropTypes.string, + }), + ...windowDimensionsPropTypes, ...withDrawerPropTypes, ...viewportOffsetTopPropTypes, @@ -104,6 +113,8 @@ const defaultProps = { policies: {}, accountManagerReportID: null, personalDetails: {}, + lastOpenedPublicRoomID: null, + session: {}, }; /** @@ -194,6 +205,13 @@ class ReportScreen extends React.Component { } fetchReportIfNeeded() { + // Re-open the last opened public room if the user logged in + if (this.props.lastOpenedPublicRoomID && !SessionUtils.isAnonymousUser(this.props.session.authTokenType)) { + Report.openReport(this.props.lastOpenedPublicRoomID); + Report.setLastOpenedPublicRoom(null); + return; + } + const reportIDFromPath = getReportID(this.props.route); // Report ID will be empty when the reports collection is empty. @@ -391,6 +409,9 @@ export default compose( withDrawerState, withNetwork(), withOnyx({ + lastOpenedPublicRoomID: { + key: ONYXKEYS.LAST_OPENED_PUBLIC_ROOM_ID, + }, isSidebarLoaded: { key: ONYXKEYS.IS_SIDEBAR_LOADED, }, @@ -417,5 +438,8 @@ export default compose( personalDetails: { key: ONYXKEYS.PERSONAL_DETAILS, }, + session: { + key: ONYXKEYS.SESSION, + }, }), )(ReportScreen); diff --git a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js index 99e11e70f5c8..937c8beddee2 100755 --- a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js +++ b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js @@ -83,7 +83,7 @@ class BaseReportActionContextMenu extends React.Component { hideContextMenu(false); InteractionManager.runAfterInteractions(() => { - Session.signOutAndRedirectToSignIn(); + Session.signOutAndRedirectToSignIn(this.props.session.authTokenType); }); } else { callback(); diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index bada391b2dab..0d55a58ae8ff 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -295,7 +295,7 @@ function ReportActionItem(props) { hideContextMenu(false); InteractionManager.runAfterInteractions(() => { - Session.signOutAndRedirectToSignIn(); + Session.signOutAndRedirectToSignIn(props.session.authTokenType); }); } else { toggleReaction(emoji); diff --git a/src/pages/home/sidebar/SidebarLinks.js b/src/pages/home/sidebar/SidebarLinks.js index b48c6b688ea3..9bf05f518e13 100644 --- a/src/pages/home/sidebar/SidebarLinks.js +++ b/src/pages/home/sidebar/SidebarLinks.js @@ -34,7 +34,6 @@ import defaultTheme from '../../../styles/themes/default'; import OptionsListSkeletonView from '../../../components/OptionsListSkeletonView'; import variables from '../../../styles/variables'; import LogoComponent from '../../../../assets/images/expensify-wordmark.svg'; -import * as SessionUtils from '../../../libs/SessionUtils'; import * as Session from '../../../libs/actions/Session'; const propTypes = { diff --git a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js index 5956bf97d2a9..e129e143e46b 100644 --- a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js +++ b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js @@ -180,7 +180,7 @@ class FloatingActionButtonAndPopover extends React.Component { */ interceptAnonymousUser(callback) { if (this.state.isAnonymousUser) { - Session.signOutAndRedirectToSignIn(); + Session.signOutAndRedirectToSignIn(this.props.session.authTokenType); } else { callback(); } From ccc1917390bd0ce0d221c47e1a99f1726426b0d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Ch=C3=A1vez?= Date: Fri, 26 May 2023 14:12:10 -0600 Subject: [PATCH 395/751] add empty space --- src/components/Reactions/AddReactionBubble.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Reactions/AddReactionBubble.js b/src/components/Reactions/AddReactionBubble.js index 208a740da1b5..dc2de5cf8102 100644 --- a/src/components/Reactions/AddReactionBubble.js +++ b/src/components/Reactions/AddReactionBubble.js @@ -117,4 +117,4 @@ export default compose( key: ONYXKEYS.SESSION, }, }) -)(AddReactionBubble); \ No newline at end of file +)(AddReactionBubble); From ec3948270704d824fdbdbaeb2995f4ca3c86b5d3 Mon Sep 17 00:00:00 2001 From: Sibtain Ali Date: Sat, 27 May 2023 01:25:01 +0500 Subject: [PATCH 396/751] feat: add AnonymouseReportFooter component --- src/components/AnonymousReportFooter.js | 55 +++++++++++++++++++++++++ src/components/AvatarWithDisplayName.js | 17 +++++++- src/components/ExpensifyWordmark.js | 11 +++++ src/languages/en.js | 3 ++ src/languages/es.js | 3 ++ src/styles/styles.js | 31 ++++++++++++++ 6 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 src/components/AnonymousReportFooter.js diff --git a/src/components/AnonymousReportFooter.js b/src/components/AnonymousReportFooter.js new file mode 100644 index 000000000000..83e190913131 --- /dev/null +++ b/src/components/AnonymousReportFooter.js @@ -0,0 +1,55 @@ +import React from 'react'; +import {View, Text} from 'react-native'; +import Button from './Button'; +import AvatarWithDisplayName from './AvatarWithDisplayName'; +import ExpensifyWordmark from './ExpensifyWordmark'; +import compose from '../libs/compose'; +import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions'; +import withLocalize, {withLocalizePropTypes} from './withLocalize'; +import reportPropTypes from '../pages/reportPropTypes'; +import CONST from '../CONST'; +import styles from '../styles/styles'; + +const propTypes = { + /** The report currently being looked at */ + report: reportPropTypes, + + ...windowDimensionsPropTypes, + ...withLocalizePropTypes, +}; + +const defaultProps = { + report: null, +}; + +const AnonymousReportFooter = (props) => ( + + + + + + + + + + {props.translate('anonymousReportFooter.logoTagline')} + + +