From 33bfa831e697afcea27c059b27d7885f5eebe391 Mon Sep 17 00:00:00 2001 From: tienifr Date: Thu, 1 Jun 2023 11:40:14 +0700 Subject: [PATCH 001/215] fix 19360 app crashes on clicking on replying thread after deleting ws --- src/libs/ReportUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index ce4debd28b39..21886511df30 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -241,7 +241,7 @@ function canDeleteReportAction(reportAction, reportID) { return true; } const report = lodashGet(allReports, `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, {}); - const policy = lodashGet(allPolicies, `${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`, {}); + const policy = lodashGet(allPolicies, `${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`) || {}; return policy.role === CONST.POLICY.ROLE.ADMIN; } From ef0dc5aa48565080447ed14b814defe637e2744d Mon Sep 17 00:00:00 2001 From: Robert Kozik Date: Tue, 6 Jun 2023 12:25:47 +0200 Subject: [PATCH 002/215] migrate PressableWithSecondaryInteraction to PressableWithFeedback --- .../index.js | 8 +++---- .../index.native.js | 21 ++++++++----------- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/components/PressableWithSecondaryInteraction/index.js b/src/components/PressableWithSecondaryInteraction/index.js index 7f43451cbadd..f97b0ac98b2c 100644 --- a/src/components/PressableWithSecondaryInteraction/index.js +++ b/src/components/PressableWithSecondaryInteraction/index.js @@ -1,10 +1,10 @@ import _ from 'underscore'; import React, {Component} from 'react'; -import {Pressable} from 'react-native'; import * as pressableWithSecondaryInteractionPropTypes from './pressableWithSecondaryInteractionPropTypes'; import styles from '../../styles/styles'; import * as DeviceCapabilities from '../../libs/DeviceCapabilities'; import * as StyleUtils from '../../styles/StyleUtils'; +import PressableWithFeedback from '../Pressable/PressableWithFeedback'; /** * This is a special Pressable that calls onSecondaryInteraction when LongPressed, or right-clicked. @@ -76,11 +76,11 @@ class PressableWithSecondaryInteraction extends Component { // On Web, Text does not support LongPress events thus manage inline mode with styling instead of using Text. return ( - (this.pressableRef = el)} @@ -88,7 +88,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 7768430c363d..1cbc57de4ef7 100644 --- a/src/components/PressableWithSecondaryInteraction/index.native.js +++ b/src/components/PressableWithSecondaryInteraction/index.native.js @@ -1,9 +1,8 @@ import _ from 'underscore'; import React, {forwardRef} from 'react'; -import {Pressable} from 'react-native'; import * as pressableWithSecondaryInteractionPropTypes from './pressableWithSecondaryInteractionPropTypes'; import Text from '../Text'; -import HapticFeedback from '../../libs/HapticFeedback'; +import PressableWithFeedback from '../Pressable/PressableWithFeedback'; /** * This is a special Pressable that calls onSecondaryInteraction when LongPressed. @@ -13,22 +12,20 @@ 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 : PressableWithFeedback; + const executeSecondaryInteraction = (e) => { + e.preventDefault(); + props.onSecondaryInteraction(e); + }; + return ( { - if (!props.onSecondaryInteraction) { - return; - } - e.preventDefault(); - HapticFeedback.longPress(); - props.onSecondaryInteraction(e); - }} + onLongPress={props.onSecondaryInteraction ? executeSecondaryInteraction : undefined} onPressIn={props.onPressIn} onPressOut={props.onPressOut} - activeOpacity={props.activeOpacity} + pressDimmingValue={props.activeOpacity} // eslint-disable-next-line react/jsx-props-no-spreading {..._.omit(props, 'onLongPress')} > From b901d2510e6bceaf614666c7cce21cd8dec380d3 Mon Sep 17 00:00:00 2001 From: Robert Kozik Date: Tue, 6 Jun 2023 12:27:21 +0200 Subject: [PATCH 003/215] add missing accessibilityLabels --- .../AnchorForCommentsOnly/BaseAnchorForCommentsOnly.js | 3 ++- src/components/LHNOptionsList/OptionRowLHN.js | 6 ++++-- src/components/MenuItem.js | 2 ++ src/components/Reactions/EmojiReactionBubble.js | 2 ++ 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/components/AnchorForCommentsOnly/BaseAnchorForCommentsOnly.js b/src/components/AnchorForCommentsOnly/BaseAnchorForCommentsOnly.js index 3886b8fab88e..e59be949f01e 100644 --- a/src/components/AnchorForCommentsOnly/BaseAnchorForCommentsOnly.js +++ b/src/components/AnchorForCommentsOnly/BaseAnchorForCommentsOnly.js @@ -60,12 +60,13 @@ const BaseAnchorForCommentsOnly = (props) => { onPress={linkProps.onPress} onPressIn={props.onPressIn} onPressOut={props.onPressOut} + accessibilityRole="link" + accessibilityLabel={props.href} > (linkRef = el)} style={StyleSheet.flatten([props.style, defaultTextStyle])} - accessibilityRole="link" hrefAttrs={{ rel: props.rel, target: isEmail ? '_self' : props.target, diff --git a/src/components/LHNOptionsList/OptionRowLHN.js b/src/components/LHNOptionsList/OptionRowLHN.js index 42e9168ba940..decbdf836df7 100644 --- a/src/components/LHNOptionsList/OptionRowLHN.js +++ b/src/components/LHNOptionsList/OptionRowLHN.js @@ -144,10 +144,12 @@ const OptionRowLHN = (props) => { props.isFocused ? styles.sidebarLinkActive : null, hovered && !props.isFocused ? props.hoverStyle : null, ]} - > + accessibilityRole="button" + accessibilityLabel={props.translate('accessibilityHints.navigatesToChat')} + > {!_.isEmpty(optionItem.icons) && diff --git a/src/components/MenuItem.js b/src/components/MenuItem.js index e672c68b6133..d28569034fb3 100644 --- a/src/components/MenuItem.js +++ b/src/components/MenuItem.js @@ -122,6 +122,8 @@ const MenuItem = (props) => { ]} disabled={props.disabled} ref={props.forwardedRef} + accessibilityRole="menuitem" + accessibilityLabel={props.title} > {({hovered, pressed}) => ( <> diff --git a/src/components/Reactions/EmojiReactionBubble.js b/src/components/Reactions/EmojiReactionBubble.js index dc60d60c2f30..dd603708cf44 100644 --- a/src/components/Reactions/EmojiReactionBubble.js +++ b/src/components/Reactions/EmojiReactionBubble.js @@ -58,6 +58,8 @@ const EmojiReactionBubble = (props) => ( enableLongPressWithHover={props.isSmallScreenWidth} // Prevent text input blur when emoji reaction is clicked onMouseDown={(e) => e.preventDefault()} + accessibilityRole="button" + accessibilityLabel={props.emojiCodes.join('')} > {props.emojiCodes.join('')} {props.count > 0 && {props.count}} From 014eb8bca162a26b3243e59e76be7ec86f812ee4 Mon Sep 17 00:00:00 2001 From: Robert Kozik Date: Tue, 6 Jun 2023 18:37:30 +0200 Subject: [PATCH 004/215] prettier --- src/components/LHNOptionsList/OptionRowLHN.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/LHNOptionsList/OptionRowLHN.js b/src/components/LHNOptionsList/OptionRowLHN.js index decbdf836df7..233efa86e3e9 100644 --- a/src/components/LHNOptionsList/OptionRowLHN.js +++ b/src/components/LHNOptionsList/OptionRowLHN.js @@ -146,7 +146,7 @@ const OptionRowLHN = (props) => { ]} accessibilityRole="button" accessibilityLabel={props.translate('accessibilityHints.navigatesToChat')} - > + > Date: Wed, 7 Jun 2023 11:20:22 +0200 Subject: [PATCH 005/215] create const values for accessibility roles --- src/CONST.js | 7 +++++++ .../AnchorForCommentsOnly/BaseAnchorForCommentsOnly.js | 3 ++- src/components/LHNOptionsList/OptionRowLHN.js | 2 +- src/components/MenuItem.js | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/CONST.js b/src/CONST.js index f4e2847ba7a5..027f14cdcbff 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -2446,6 +2446,13 @@ const CONST = { EXPENSIFY_LOGO_SIZE_RATIO: 0.22, EXPENSIFY_LOGO_MARGIN_RATIO: 0.03, }, + ACCESSIBILITY_ROLE: { + BUTTON: 'button', + LINK: 'link', + MENUITEM: 'menuitem', + TEXT: 'text', + RADIO: 'radio', + }, }; export default CONST; diff --git a/src/components/AnchorForCommentsOnly/BaseAnchorForCommentsOnly.js b/src/components/AnchorForCommentsOnly/BaseAnchorForCommentsOnly.js index e59be949f01e..8359150bb786 100644 --- a/src/components/AnchorForCommentsOnly/BaseAnchorForCommentsOnly.js +++ b/src/components/AnchorForCommentsOnly/BaseAnchorForCommentsOnly.js @@ -13,6 +13,7 @@ import * as DeviceCapabilities from '../../libs/DeviceCapabilities'; import styles from '../../styles/styles'; import withWindowDimensions, {windowDimensionsPropTypes} from '../withWindowDimensions'; import {propTypes as anchorForCommentsOnlyPropTypes, defaultProps as anchorForCommentsOnlyDefaultProps} from './anchorForCommentsOnlyPropTypes'; +import CONST from '../../CONST'; const propTypes = { /** Press in handler for the link */ @@ -60,7 +61,7 @@ const BaseAnchorForCommentsOnly = (props) => { onPress={linkProps.onPress} onPressIn={props.onPressIn} onPressOut={props.onPressOut} - accessibilityRole="link" + accessibilityRole={CONST.ACCESSIBILITY_ROLE.LINK} accessibilityLabel={props.href} > diff --git a/src/components/LHNOptionsList/OptionRowLHN.js b/src/components/LHNOptionsList/OptionRowLHN.js index 233efa86e3e9..9f7cdcb6a82b 100644 --- a/src/components/LHNOptionsList/OptionRowLHN.js +++ b/src/components/LHNOptionsList/OptionRowLHN.js @@ -144,7 +144,7 @@ const OptionRowLHN = (props) => { props.isFocused ? styles.sidebarLinkActive : null, hovered && !props.isFocused ? props.hoverStyle : null, ]} - accessibilityRole="button" + accessibilityRole={CONST.ACCESSIBILITY_ROLE.BUTTON} accessibilityLabel={props.translate('accessibilityHints.navigatesToChat')} > { ]} disabled={props.disabled} ref={props.forwardedRef} - accessibilityRole="menuitem" + accessibilityRole={CONST.ACCESSIBILITY_ROLE.MENUITEM} accessibilityLabel={props.title} > {({hovered, pressed}) => ( From cac624ca1d46ea6eecebe27d028b126c10aed0be Mon Sep 17 00:00:00 2001 From: Robert Kozik Date: Mon, 12 Jun 2023 11:05:06 +0200 Subject: [PATCH 006/215] add possibility to pass components as functions to PressableWithFeedback --- src/components/Pressable/PressableWithFeedback.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Pressable/PressableWithFeedback.js b/src/components/Pressable/PressableWithFeedback.js index 281492568867..44ef8694582c 100644 --- a/src/components/Pressable/PressableWithFeedback.js +++ b/src/components/Pressable/PressableWithFeedback.js @@ -73,7 +73,7 @@ const PressableWithFeedback = forwardRef((props, ref) => { ...(state.focused ? StyleUtils.parseStyleAsArray(props.focusStyle, state) : []), ]} > - {props.children} + {_.isFunction(props.children) ? props.children(state) : props.children} )} From e94aa5b0bb89434973b30773706ca32d138493a3 Mon Sep 17 00:00:00 2001 From: Robert Kozik Date: Mon, 12 Jun 2023 11:05:21 +0200 Subject: [PATCH 007/215] move accessibilityLabel to PressableWithFeedback component --- src/pages/home/report/ReportActionItem.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index e7c704fd8c8e..b1b02620dfea 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -423,10 +423,11 @@ function ReportActionItem(props) { onSecondaryInteraction={showPopover} preventDefaultContextMenu={!props.draftMessage && !hasErrors} withoutFocusOnSecondaryInteraction + accessibilityLabel={props.translate('accessibilityHints.chatMessage')} > {(hovered) => ( - + {props.shouldDisplayNewMarker && } Date: Mon, 12 Jun 2023 11:05:32 +0200 Subject: [PATCH 008/215] disable dimming on hover for PeessableWithSecondaryInteraction --- src/components/PressableWithSecondaryInteraction/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/PressableWithSecondaryInteraction/index.js b/src/components/PressableWithSecondaryInteraction/index.js index 6c37b9e2504d..5246e3bfb9a2 100644 --- a/src/components/PressableWithSecondaryInteraction/index.js +++ b/src/components/PressableWithSecondaryInteraction/index.js @@ -86,6 +86,7 @@ class PressableWithSecondaryInteraction extends Component { // eslint-disable-next-line react/jsx-props-no-spreading {...defaultPressableProps} style={(state) => [StyleUtils.parseStyleFromFunction(this.props.style, state), ...[this.props.inline && styles.dInline]]} + hoverDimmingValue={1} > {this.props.children} From 87466568f3ad5a9f566c6e68ae9698373c9ee00b Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Mon, 12 Jun 2023 22:57:22 +0700 Subject: [PATCH 009/215] fix: move comment --- ios/Podfile.lock | 6 +++--- src/components/AttachmentCarousel/index.js | 6 +++++- src/components/AttachmentView.js | 4 ++++ src/components/PDFView/PDFPasswordForm.js | 16 ++++++++++++++++ src/components/PDFView/index.js | 1 + src/components/PDFView/index.native.js | 1 + src/components/PDFView/pdfViewPropTypes.js | 3 +++ src/libs/Permissions.js | 2 +- 8 files changed, 34 insertions(+), 5 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 6cb4235c58c8..c6c8ee0b4dce 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1019,7 +1019,7 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Airship: c70eed50e429f97f5adb285423c7291fb7a032ae AirshipFrameworkProxy: 7bc4130c668c6c98e2d4c60fe4c9eb61a999be99 - boost: a7c83b31436843459a1961bfd74b96033dc77234 + boost: 57d2868c099736d80fcd648bf211b4431e51a558 CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54 FBLazyVector: ff54429f0110d3c722630a98096ba689c39f6d5f @@ -1062,7 +1062,7 @@ SPEC CHECKSUMS: Permission-LocationWhenInUse: 3ba99e45c852763f730eabecec2870c2382b7bd4 Plaid: 7d340abeadb46c7aa1a91f896c5b22395a31fcf2 PromisesObjC: 09985d6d70fbe7878040aa746d78236e6946d2ef - RCT-Folly: 0080d0a6ebf2577475bda044aa59e2ca1f909cda + RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1 RCTRequired: e9e7b8b45aa9bedb2fdad71740adf07a7265b9be RCTTypeSafety: 9ae0e9206625e995f0df4d5b9ddc94411929fb30 React: a71c8e1380f07e01de721ccd52bcf9c03e81867d @@ -1135,4 +1135,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 4ed1c7b099741c82e2b0411b95f6468e72be6c76 -COCOAPODS: 1.12.0 +COCOAPODS: 1.11.3 diff --git a/src/components/AttachmentCarousel/index.js b/src/components/AttachmentCarousel/index.js index 77ab66400ae2..6b63b1cc5731 100644 --- a/src/components/AttachmentCarousel/index.js +++ b/src/components/AttachmentCarousel/index.js @@ -1,5 +1,5 @@ import React from 'react'; -import {View, FlatList, PixelRatio} from 'react-native'; +import {View, FlatList, PixelRatio, Keyboard} from 'react-native'; import PropTypes from 'prop-types'; import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; @@ -212,6 +212,7 @@ class AttachmentCarousel extends React.Component { * @param {Array<{item: {source, file}, index: Number}>} viewableItems */ updatePage({viewableItems}) { + console.log("updatePage") // Since we can have only one item in view at a time, we can use the first item in the array // to get the index of the current page const entry = _.first(viewableItems); @@ -222,6 +223,7 @@ class AttachmentCarousel extends React.Component { const page = entry.index; this.props.onNavigate(entry.item); this.setState({page, isZoomed: false}); + Keyboard.dismiss() } /** @@ -252,6 +254,7 @@ class AttachmentCarousel extends React.Component { renderItem({item}) { return ( 0 && ( {}, onToggleKeyboard: () => {}, containerStyles: [], + isFocused: false }; const AttachmentView = (props) => { @@ -82,9 +84,11 @@ const AttachmentView = (props) => { // will appear with a source that is a blob if (Str.isPDF(props.source) || (props.file && Str.isPDF(props.file.name || props.translate('attachmentView.unknownFilename')))) { const sourceURL = props.isAuthTokenRequired ? addEncryptedAuthTokenToURL(props.source) : props.source; + console.log("AttachmentView: ", props.isFocused) const children = ( {this.props.translate('attachmentView.pdfPasswordForm.formLabel')} (this.textInputRef = el)} label={this.props.translate('common.password')} autoComplete="off" autoCorrect={false} diff --git a/src/components/PDFView/index.js b/src/components/PDFView/index.js index 85821b8d8ca3..aad57d0344e8 100644 --- a/src/components/PDFView/index.js +++ b/src/components/PDFView/index.js @@ -150,6 +150,7 @@ class PDFView extends Component { {this.state.shouldRequestPassword && ( this.setState({isPasswordInvalid: false})} isPasswordInvalid={this.state.isPasswordInvalid} diff --git a/src/components/PDFView/index.native.js b/src/components/PDFView/index.native.js index 7f9f33fca6f6..b668e9109470 100644 --- a/src/components/PDFView/index.native.js +++ b/src/components/PDFView/index.native.js @@ -158,6 +158,7 @@ class PDFView extends Component { {this.state.shouldRequestPassword && ( this.setState({isPasswordInvalid: false})} isPasswordInvalid={this.state.isPasswordInvalid} diff --git a/src/components/PDFView/pdfViewPropTypes.js b/src/components/PDFView/pdfViewPropTypes.js index f87cee3a11b6..0b1cb1ca7ad2 100644 --- a/src/components/PDFView/pdfViewPropTypes.js +++ b/src/components/PDFView/pdfViewPropTypes.js @@ -21,6 +21,8 @@ const propTypes = { /** Handles load complete event in PDF component */ onLoadComplete: PropTypes.func, + isFocused: PropTypes.bool, + ...windowDimensionsPropTypes, }; @@ -31,6 +33,7 @@ const defaultProps = { onToggleKeyboard: () => {}, onScaleChanged: () => {}, onLoadComplete: () => {}, + isFocused: false }; export {propTypes, defaultProps}; diff --git a/src/libs/Permissions.js b/src/libs/Permissions.js index d3e407260e20..cf4904cce6e5 100644 --- a/src/libs/Permissions.js +++ b/src/libs/Permissions.js @@ -99,7 +99,7 @@ function canUsePasswordlessLogins(betas) { * @returns {Boolean} */ function canUseTasks(betas) { - return _.contains(betas, CONST.BETAS.TASKS) || _.contains(betas, CONST.BETAS.ALL); + return true } export default { From 909d7c95f8e65460734b2f0f077a7a1b34f5ef65 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Mon, 12 Jun 2023 23:28:18 +0700 Subject: [PATCH 010/215] fix: update --- src/components/AttachmentCarousel/index.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/components/AttachmentCarousel/index.js b/src/components/AttachmentCarousel/index.js index 6b63b1cc5731..cc8b069caa54 100644 --- a/src/components/AttachmentCarousel/index.js +++ b/src/components/AttachmentCarousel/index.js @@ -187,6 +187,7 @@ class AttachmentCarousel extends React.Component { shouldShowArrow: this.canUseTouchScreen, containerWidth: 0, isZoomed: false, + activeSource: null }; } @@ -212,18 +213,20 @@ class AttachmentCarousel extends React.Component { * @param {Array<{item: {source, file}, index: Number}>} viewableItems */ updatePage({viewableItems}) { - console.log("updatePage") + Keyboard.dismiss(); + console.log("updatePage", viewableItems) // Since we can have only one item in view at a time, we can use the first item in the array // to get the index of the current page const entry = _.first(viewableItems); if (!entry) { + this.setState({ activeSource: null }); return; } + console.log('entry.item', entry.item); const page = entry.index; this.props.onNavigate(entry.item); - this.setState({page, isZoomed: false}); - Keyboard.dismiss() + this.setState({page, isZoomed: false, activeSource: entry.item.source}); } /** @@ -254,7 +257,7 @@ class AttachmentCarousel extends React.Component { renderItem({item}) { return ( Date: Tue, 13 Jun 2023 11:01:33 +0200 Subject: [PATCH 011/215] move PressableWithDelayToggle to components/Pressable directory --- src/components/CopyTextToClipboard.js | 2 +- .../PressableWithDelayToggle.js | 22 +++++++++---------- src/components/Pressable/index.js | 1 + .../Security/TwoFactorAuth/CodesPage.js | 2 +- .../Security/TwoFactorAuth/VerifyPage.js | 2 +- 5 files changed, 15 insertions(+), 14 deletions(-) rename src/components/{ => Pressable}/PressableWithDelayToggle.js (90%) diff --git a/src/components/CopyTextToClipboard.js b/src/components/CopyTextToClipboard.js index 1f9affab67d4..2c82b2be4828 100644 --- a/src/components/CopyTextToClipboard.js +++ b/src/components/CopyTextToClipboard.js @@ -1,7 +1,7 @@ import React, {useCallback} from 'react'; import PropTypes from 'prop-types'; import * as Expensicons from './Icon/Expensicons'; -import PressableWithDelayToggle from './PressableWithDelayToggle'; +import PressableWithDelayToggle from './Pressable/PressableWithDelayToggle'; import Clipboard from '../libs/Clipboard'; import withLocalize, {withLocalizePropTypes} from './withLocalize'; diff --git a/src/components/PressableWithDelayToggle.js b/src/components/Pressable/PressableWithDelayToggle.js similarity index 90% rename from src/components/PressableWithDelayToggle.js rename to src/components/Pressable/PressableWithDelayToggle.js index 57f561ec91ac..e909ae6da3f6 100644 --- a/src/components/PressableWithDelayToggle.js +++ b/src/components/Pressable/PressableWithDelayToggle.js @@ -1,17 +1,17 @@ import React from 'react'; import PropTypes from 'prop-types'; import {Pressable} from 'react-native'; -import * as Expensicons from './Icon/Expensicons'; -import compose from '../libs/compose'; -import Icon from './Icon'; -import Tooltip from './Tooltip'; -import Text from './Text'; -import styles from '../styles/styles'; -import variables from '../styles/variables'; -import getButtonState from '../libs/getButtonState'; -import * as StyleUtils from '../styles/StyleUtils'; -import withLocalize, {withLocalizePropTypes} from './withLocalize'; -import withDelayToggleButtonState, {withDelayToggleButtonStatePropTypes} from './withDelayToggleButtonState'; +import * as Expensicons from '../Icon/Expensicons'; +import compose from '../../libs/compose'; +import Icon from '../Icon'; +import Tooltip from '../Tooltip'; +import Text from '../Text'; +import styles from '../../styles/styles'; +import variables from '../../styles/variables'; +import getButtonState from '../../libs/getButtonState'; +import * as StyleUtils from '../../styles/StyleUtils'; +import withLocalize, {withLocalizePropTypes} from '../withLocalize'; +import withDelayToggleButtonState, {withDelayToggleButtonStatePropTypes} from '../withDelayToggleButtonState'; const propTypes = { ...withLocalizePropTypes, diff --git a/src/components/Pressable/index.js b/src/components/Pressable/index.js index 83f597b3de8d..e0420ac05edd 100644 --- a/src/components/Pressable/index.js +++ b/src/components/Pressable/index.js @@ -1,3 +1,4 @@ export {default as GenericPressable} from './GenericPressable'; export {default as PressableWithFeedback} from './PressableWithFeedback'; export {default as PressableWithoutFeedback} from './PressableWithoutFeedback'; +export {default as PressableWithDelayToggle} from './PressableWithDelayToggle'; diff --git a/src/pages/settings/Security/TwoFactorAuth/CodesPage.js b/src/pages/settings/Security/TwoFactorAuth/CodesPage.js index 02911676d430..b8767e469ba5 100644 --- a/src/pages/settings/Security/TwoFactorAuth/CodesPage.js +++ b/src/pages/settings/Security/TwoFactorAuth/CodesPage.js @@ -17,7 +17,7 @@ import withWindowDimensions, {windowDimensionsPropTypes} from '../../../../compo import styles from '../../../../styles/styles'; import FixedFooter from '../../../../components/FixedFooter'; import Button from '../../../../components/Button'; -import PressableWithDelayToggle from '../../../../components/PressableWithDelayToggle'; +import PressableWithDelayToggle from '../../../../components/Pressable/PressableWithDelayToggle'; import Text from '../../../../components/Text'; import Section from '../../../../components/Section'; import ONYXKEYS from '../../../../ONYXKEYS'; diff --git a/src/pages/settings/Security/TwoFactorAuth/VerifyPage.js b/src/pages/settings/Security/TwoFactorAuth/VerifyPage.js index d3a53a0a03be..ee412c69db10 100644 --- a/src/pages/settings/Security/TwoFactorAuth/VerifyPage.js +++ b/src/pages/settings/Security/TwoFactorAuth/VerifyPage.js @@ -18,7 +18,7 @@ import TextLink from '../../../../components/TextLink'; import Clipboard from '../../../../libs/Clipboard'; import FixedFooter from '../../../../components/FixedFooter'; import * as Expensicons from '../../../../components/Icon/Expensicons'; -import PressableWithDelayToggle from '../../../../components/PressableWithDelayToggle'; +import PressableWithDelayToggle from '../../../../components/Pressable/PressableWithDelayToggle'; import TwoFactorAuthForm from './TwoFactorAuthForm'; import QRCode from '../../../../components/QRCode'; import expensifyLogo from '../../../../../assets/images/expensify-logo-round-transparent.png'; From cc6f0aa8df8618d0885563ddb2e516071f5e2644 Mon Sep 17 00:00:00 2001 From: Robert Kozik Date: Tue, 13 Jun 2023 11:06:25 +0200 Subject: [PATCH 012/215] migrate PressableWithDelayToggle to PressableWithoutFeedback --- .../Pressable/PressableWithDelayToggle.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/components/Pressable/PressableWithDelayToggle.js b/src/components/Pressable/PressableWithDelayToggle.js index e909ae6da3f6..740e1cd391c7 100644 --- a/src/components/Pressable/PressableWithDelayToggle.js +++ b/src/components/Pressable/PressableWithDelayToggle.js @@ -1,6 +1,5 @@ import React from 'react'; import PropTypes from 'prop-types'; -import {Pressable} from 'react-native'; import * as Expensicons from '../Icon/Expensicons'; import compose from '../../libs/compose'; import Icon from '../Icon'; @@ -12,6 +11,7 @@ import getButtonState from '../../libs/getButtonState'; import * as StyleUtils from '../../styles/StyleUtils'; import withLocalize, {withLocalizePropTypes} from '../withLocalize'; import withDelayToggleButtonState, {withDelayToggleButtonStatePropTypes} from '../withDelayToggleButtonState'; +import PressableWithoutFeedback from './PressableWithoutFeedback'; const propTypes = { ...withLocalizePropTypes, @@ -84,16 +84,19 @@ function PressableWithDelayToggle(props) { // Due to limitations in RN regarding the vertical text alignment of non-Text elements, // for elements that are supposed to be inline, we need to use a Text element instead // of a Pressable - const PressableView = props.inline ? Text : Pressable; + const PressableView = props.inline ? Text : PressableWithoutFeedback; + const tooltipText = props.isDelayButtonStateComplete ? props.tooltipTextChecked : props.tooltipText; return ( <> {props.isDelayButtonStateComplete && props.textChecked ? props.textChecked : props.text} - {({hovered, pressed}) => ( @@ -121,7 +123,7 @@ function PressableWithDelayToggle(props) { )} )} - + From 42fb09dff043c6f2735659348a25ad73cbf1aac2 Mon Sep 17 00:00:00 2001 From: Robert Kozik Date: Tue, 13 Jun 2023 20:27:58 +0200 Subject: [PATCH 013/215] disable text selection for touch devices in PressableWithSecondaryInteraction --- src/components/PressableWithSecondaryInteraction/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/PressableWithSecondaryInteraction/index.js b/src/components/PressableWithSecondaryInteraction/index.js index df42d8ff85eb..a97f36fa7dd8 100644 --- a/src/components/PressableWithSecondaryInteraction/index.js +++ b/src/components/PressableWithSecondaryInteraction/index.js @@ -1,5 +1,5 @@ import _ from 'underscore'; -import React, {Component, Pressable} from 'react'; +import React, {Component} from 'react'; import * as pressableWithSecondaryInteractionPropTypes from './pressableWithSecondaryInteractionPropTypes'; import styles from '../../styles/styles'; import * as DeviceCapabilities from '../../libs/DeviceCapabilities'; @@ -78,6 +78,7 @@ class PressableWithSecondaryInteraction extends Component { return ( Date: Tue, 13 Jun 2023 19:08:53 -0400 Subject: [PATCH 014/215] add 30 second timer before allowing user to resend themselves a validate code --- .../ValidateCodeForm/BaseValidateCodeForm.js | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js b/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js index 49a1a4fb693a..935757b821ef 100755 --- a/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js +++ b/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js @@ -68,7 +68,7 @@ function BaseValidateCodeForm(props) { const [formError, setFormError] = useState({}); const [validateCode, setValidateCode] = useState(props.credentials.validateCode || ''); const [twoFactorAuthCode, setTwoFactorAuthCode] = useState(''); - const [linkSent, setLinkSent] = useState(false); + const [timeRemaining, setTimeRemaining] = useState(30); const prevIsVisible = usePrevious(props.isVisible); const prevRequiresTwoFactorAuth = usePrevious(props.account.requiresTwoFactorAuth); @@ -76,6 +76,7 @@ function BaseValidateCodeForm(props) { const inputValidateCodeRef = useRef(); const input2FARef = useRef(); + const timerRef = useRef(timeRemaining); useEffect(() => { if (!inputValidateCodeRef.current || prevIsVisible || !props.isVisible || !canFocusInputOnScreenFocus()) { @@ -94,10 +95,10 @@ function BaseValidateCodeForm(props) { } // Clear the code input if magic code valid or a new magic code was requested - if ((prevIsVisible && !props.isVisible) || (props.isVisible && linkSent && props.account.message)) { + if ((prevIsVisible && !props.isVisible) || (props.isVisible && timeRemaining === 30 && props.account.message)) { setValidateCode(''); } - }, [props.isVisible, props.account.message, prevIsVisible, linkSent, validateCode]); + }, [props.isVisible, props.account.message, prevIsVisible, timeRemaining, validateCode]); useEffect(() => { if (prevValidateCode || !props.credentials.validateCode) { @@ -127,6 +128,18 @@ function BaseValidateCodeForm(props) { input2FARef.current.clear(); }, [twoFactorAuthCode]); + useEffect(() => { + timerRef.current = setInterval(() => { + if (timeRemaining < 0) { + clearInterval(timerRef.current); + } else { + setTimeRemaining((timeRemaining) => timeRemaining - 1); + } + }, 1000); + + return () => {clearInterval(timerRef.current)}; + }, [timeRemaining]); + /** * Handle text input and clear formError upon text change * @@ -137,7 +150,6 @@ function BaseValidateCodeForm(props) { const setInput = key === 'validateCode' ? setValidateCode : setTwoFactorAuthCode; setInput(text); setFormError((prevError) => ({...prevError, [key]: ''})); - setLinkSent(false); if (props.account.errors) { Session.clearAccountMessages(); @@ -153,7 +165,7 @@ function BaseValidateCodeForm(props) { User.resendValidateCode(props.credentials.login, true); // Give feedback to the user to let them know the email was sent so they don't spam the button. - setLinkSent(true); + setTimeRemaining(30); }; /** @@ -242,8 +254,11 @@ function BaseValidateCodeForm(props) { autoFocus /> - {linkSent ? ( - {props.account.message ? props.translate(props.account.message) : ''} + {timeRemaining > 0 ? ( + + {props.translate('validateCodeForm.requestNewCode')} + 00:{String(timeRemaining).padStart(2, '0')} + ) : ( Date: Tue, 13 Jun 2023 19:09:10 -0400 Subject: [PATCH 015/215] add translations --- src/languages/en.js | 2 +- src/languages/es.js | 2 +- src/libs/actions/Session/index.js | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/languages/en.js b/src/languages/en.js index 4602931ff120..f5f6d9f2f4a0 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -692,7 +692,7 @@ export default { magicCodeNotReceived: "Didn't receive a magic code?", enterAuthenticatorCode: 'Please enter your authenticator code', requiredWhen2FAEnabled: 'Required when 2FA is enabled', - codeSent: 'Magic code sent!', + requestNewCode: 'Request a new code in ', error: { pleaseFillMagicCode: 'Please enter your magic code', incorrectMagicCode: 'Incorrect magic code.', diff --git a/src/languages/es.js b/src/languages/es.js index a787607c465d..51e9e6c59a82 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -693,7 +693,7 @@ export default { magicCodeNotReceived: '¿No recibiste un código mágico?', enterAuthenticatorCode: 'Por favor, introduce el código de autenticador', requiredWhen2FAEnabled: 'Obligatorio cuando A2F está habilitado', - codeSent: '¡Código mágico enviado!', + requestNewCode: 'Pedir un código nuevo en ', error: { pleaseFillMagicCode: 'Por favor, introduce el código mágico', incorrectMagicCode: 'Código mágico incorrecto.', diff --git a/src/libs/actions/Session/index.js b/src/libs/actions/Session/index.js index b53d7811ef8d..4361913403b5 100644 --- a/src/libs/actions/Session/index.js +++ b/src/libs/actions/Session/index.js @@ -178,7 +178,6 @@ function resendValidateCode(login = credentials.login) { key: ONYXKEYS.ACCOUNT, value: { isLoading: false, - message: 'validateCodeForm.codeSent', loadingForm: null, }, }, From 36e74985cd8f6d6b0771fc794a557d1b67d2f935 Mon Sep 17 00:00:00 2001 From: Nikki Wines Date: Tue, 13 Jun 2023 19:09:23 -0400 Subject: [PATCH 016/215] add/modify styles --- src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js | 3 +-- src/styles/styles.js | 4 ++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js b/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js index 935757b821ef..8a9ba646cd04 100755 --- a/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js +++ b/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js @@ -253,6 +253,7 @@ function BaseValidateCodeForm(props) { hasError={hasError} autoFocus /> + {hasError && } {timeRemaining > 0 ? ( @@ -276,8 +277,6 @@ function BaseValidateCodeForm(props) { )} - - {hasError && }