diff --git a/patches/react-native-draggable-flatlist+4.0.1.patch b/patches/react-native-draggable-flatlist+4.0.1+001+initial.patch similarity index 100% rename from patches/react-native-draggable-flatlist+4.0.1.patch rename to patches/react-native-draggable-flatlist+4.0.1+001+initial.patch diff --git a/patches/react-native-draggable-flatlist+4.0.1+002+fix-console-error-ref-measureLayout.patch b/patches/react-native-draggable-flatlist+4.0.1+002+fix-console-error-ref-measureLayout.patch new file mode 100644 index 000000000000..883594ac044d --- /dev/null +++ b/patches/react-native-draggable-flatlist+4.0.1+002+fix-console-error-ref-measureLayout.patch @@ -0,0 +1,16 @@ +diff --git a/node_modules/react-native-draggable-flatlist/src/components/NestableDraggableFlatList.tsx b/node_modules/react-native-draggable-flatlist/src/components/NestableDraggableFlatList.tsx +index 1559352..b84ee99 100644 +--- a/node_modules/react-native-draggable-flatlist/src/components/NestableDraggableFlatList.tsx ++++ b/node_modules/react-native-draggable-flatlist/src/components/NestableDraggableFlatList.tsx +@@ -56,6 +56,11 @@ function NestableDraggableFlatListInner( + const onFail = () => { + console.log("## nested draggable list measure fail"); + }; ++ ++ if (typeof nodeHandle === "number" ) { ++ return; ++ } ++ + //@ts-ignore + containerRef.current.measureLayout(nodeHandle, onSuccess, onFail); + }); diff --git a/src/components/AvatarWithDisplayName.tsx b/src/components/AvatarWithDisplayName.tsx index e9b3b555385d..a8b3e1d35119 100644 --- a/src/components/AvatarWithDisplayName.tsx +++ b/src/components/AvatarWithDisplayName.tsx @@ -29,6 +29,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {Policy, Report} from '@src/types/onyx'; import type {Icon} from '@src/types/onyx/OnyxCommon'; +import {getButtonRole} from './Button/utils'; import CaretWrapper from './CaretWrapper'; import DisplayNames from './DisplayNames'; import {FallbackAvatar} from './Icon/Expensicons'; @@ -134,22 +135,24 @@ function AvatarWithDisplayName({policy, report, isAnonymous = false, size = CONS - {shouldShowSubscriptAvatar ? ( - - ) : ( - - )} + + {shouldShowSubscriptAvatar ? ( + + ) : ( + + )} + diff --git a/src/components/Button/index.tsx b/src/components/Button/index.tsx index b98baab062ba..76ba73152335 100644 --- a/src/components/Button/index.tsx +++ b/src/components/Button/index.tsx @@ -17,6 +17,7 @@ import HapticFeedback from '@libs/HapticFeedback'; import CONST from '@src/CONST'; import type ChildrenProps from '@src/types/utils/ChildrenProps'; import type IconAsset from '@src/types/utils/IconAsset'; +import {getButtonRole, getButtonStyle} from './utils'; import validateSubmitShortcut from './validateSubmitShortcut'; type ButtonProps = Partial & { @@ -146,6 +147,9 @@ type ButtonProps = Partial & { /** Whether the Enter keyboard listening is active whether or not the screen that contains the button is focused */ isPressOnEnterActive?: boolean; + /** Whether is a nested button inside other button, since nesting buttons isn't valid html */ + isNested?: boolean; + /** The text displays under the first line */ secondLineText?: string; }; @@ -249,6 +253,7 @@ function Button( link = false, isContentCentered = false, isPressOnEnterActive, + isNested = false, secondLineText = '', ...rest }: ButtonProps, @@ -414,10 +419,10 @@ function Button( isDisabled && !danger && !success ? styles.buttonDisabled : undefined, shouldRemoveRightBorderRadius ? styles.noRightBorderRadius : undefined, shouldRemoveLeftBorderRadius ? styles.noLeftBorderRadius : undefined, - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing text && shouldShowRightIcon ? styles.alignItemsStretch : undefined, innerStyles, link && styles.bgTransparent, + getButtonStyle(styles, isNested), ]} hoverStyle={[ shouldUseDefaultHover && !isDisabled ? styles.buttonDefaultHovered : undefined, @@ -429,7 +434,7 @@ function Button( id={id} testID={testID} accessibilityLabel={accessibilityLabel} - role={CONST.ROLE.BUTTON} + role={getButtonRole(isNested)} hoverDimmingValue={1} onHoverIn={() => setIsHovered(true)} onHoverOut={() => setIsHovered(false)} diff --git a/src/components/Button/utils/index.ts b/src/components/Button/utils/index.ts new file mode 100644 index 000000000000..4eeafe89dc19 --- /dev/null +++ b/src/components/Button/utils/index.ts @@ -0,0 +1,6 @@ +import CONST from '@src/CONST'; +import type {GetButtonRole, GetButtonStyle} from './types'; + +const getButtonStyle: GetButtonStyle = () => undefined; +const getButtonRole: GetButtonRole = () => CONST.ROLE.BUTTON; +export {getButtonStyle, getButtonRole}; diff --git a/src/components/Button/utils/index.web.ts b/src/components/Button/utils/index.web.ts new file mode 100644 index 000000000000..0eb9740e69bd --- /dev/null +++ b/src/components/Button/utils/index.web.ts @@ -0,0 +1,7 @@ +import CONST from '@src/CONST'; +import type {GetButtonRole, GetButtonStyle} from './types'; + +const getButtonStyle: GetButtonStyle = (styles, isNested) => (isNested ? styles.cursorPointer : undefined); +const getButtonRole: GetButtonRole = (isNested) => (isNested ? CONST.ROLE.PRESENTATION : CONST.ROLE.BUTTON); + +export {getButtonStyle, getButtonRole}; diff --git a/src/components/Button/utils/types.ts b/src/components/Button/utils/types.ts new file mode 100644 index 000000000000..06d7a54a2073 --- /dev/null +++ b/src/components/Button/utils/types.ts @@ -0,0 +1,7 @@ +import type {Role, StyleProp, ViewStyle} from 'react-native'; + +type GetButtonStyle = (styles: {cursorPointer: ViewStyle}, isNested: boolean) => StyleProp | undefined; + +type GetButtonRole = (isNested: boolean) => Role | undefined; + +export type {GetButtonStyle, GetButtonRole}; diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/DeletedActionRenderer.tsx b/src/components/HTMLEngineProvider/HTMLRenderers/DeletedActionRenderer.tsx index 4e6334d90ebd..6c3528437a01 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/DeletedActionRenderer.tsx +++ b/src/components/HTMLEngineProvider/HTMLRenderers/DeletedActionRenderer.tsx @@ -43,7 +43,14 @@ function DeletedActionRenderer({tnode}: CustomRendererProps) const data = firstChild && 'data' in firstChild ? firstChild.data : null; if (typeof data === 'string') { - return {data}; + return ( + + {data} + + ); } return props.childElement; }} diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.tsx b/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.tsx index 4c8e941acb87..d9d079549d8d 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.tsx +++ b/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.tsx @@ -3,6 +3,7 @@ import {useOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; import type {CustomRendererProps, TBlock} from 'react-native-render-html'; import {AttachmentContext} from '@components/AttachmentContext'; +import {getButtonRole, getButtonStyle} from '@components/Button/utils'; import {isDeletedNode} from '@components/HTMLEngineProvider/htmlEngineUtils'; import * as Expensicons from '@components/Icon/Expensicons'; import PressableWithoutFocus from '@components/Pressable/PressableWithoutFocus'; @@ -11,9 +12,9 @@ import ThumbnailImage from '@components/ThumbnailImage'; import useLocalize from '@hooks/useLocalize'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import * as FileUtils from '@libs/fileDownload/FileUtils'; +import {getFileName, getFileType, splitExtensionFromFileName} from '@libs/fileDownload/FileUtils'; import Navigation from '@libs/Navigation/Navigation'; -import * as ReportUtils from '@libs/ReportUtils'; +import {isArchivedNonExpenseReport} from '@libs/ReportUtils'; import tryResolveUrlFromApiRoot from '@libs/tryResolveUrlFromApiRoot'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -70,12 +71,12 @@ function ImageRenderer({tnode}: ImageRendererProps) { const imageHeight = (htmlAttribs['data-expensify-height'] && parseInt(htmlAttribs['data-expensify-height'], 10)) || undefined; const imagePreviewModalDisabled = htmlAttribs['data-expensify-preview-modal-disabled'] === 'true'; - const fileType = FileUtils.getFileType(attachmentSourceAttribute); + const fileType = getFileType(attachmentSourceAttribute); const fallbackIcon = fileType === CONST.ATTACHMENT_FILE_TYPE.FILE ? Expensicons.Document : Expensicons.GalleryNotFound; const theme = useTheme(); - let fileName = htmlAttribs[CONST.ATTACHMENT_ORIGINAL_FILENAME_ATTRIBUTE] || FileUtils.getFileName(`${isAttachmentOrReceipt ? attachmentSourceAttribute : htmlAttribs.src}`); - const fileInfo = FileUtils.splitExtensionFromFileName(fileName); + let fileName = htmlAttribs[CONST.ATTACHMENT_ORIGINAL_FILENAME_ATTRIBUTE] || getFileName(`${isAttachmentOrReceipt ? attachmentSourceAttribute : htmlAttribs.src}`); + const fileInfo = splitExtensionFromFileName(fileName); if (!fileInfo.fileExtension) { fileName = `${fileInfo?.fileName || CONST.DEFAULT_IMAGE_FILE_NAME}.jpg`; } @@ -103,7 +104,7 @@ function ImageRenderer({tnode}: ImageRendererProps) { {({reportID, accountID, type}) => ( { if (!source || !type) { return; @@ -117,17 +118,10 @@ function ImageRenderer({tnode}: ImageRendererProps) { if (isDisabled) { return; } - showContextMenuForReport( - event, - anchor, - report?.reportID, - action, - checkIfContextMenuActive, - ReportUtils.isArchivedNonExpenseReport(report, reportNameValuePairs), - ); + showContextMenuForReport(event, anchor, report?.reportID, action, checkIfContextMenuActive, isArchivedNonExpenseReport(report, reportNameValuePairs)); }} shouldUseHapticsOnLongPress - accessibilityRole={CONST.ROLE.BUTTON} + role={getButtonRole(true)} accessibilityLabel={translate('accessibilityHints.viewAttachment')} > {thumbnailImageComponent} diff --git a/src/components/MoneyRequestConfirmationListFooter.tsx b/src/components/MoneyRequestConfirmationListFooter.tsx index 74d403099316..780571d9b4a8 100644 --- a/src/components/MoneyRequestConfirmationListFooter.tsx +++ b/src/components/MoneyRequestConfirmationListFooter.tsx @@ -328,33 +328,33 @@ function MoneyRequestConfirmationListFooter({ }, { item: ( - - - { - if (!transactionID) { - return; - } - - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_DESCRIPTION.getRoute(action, iouType, transactionID, reportID, Navigation.getActiveRoute(), reportActionID)); - }} - style={[styles.moneyRequestMenuItem]} - titleStyle={styles.flex1} - disabled={didConfirm} - interactive={!isReadOnly} - numberOfLinesTitle={2} - /> - - + + + + { + if (!transactionID) { + return; + } + + Navigation.navigate( + ROUTES.MONEY_REQUEST_STEP_DESCRIPTION.getRoute(action, iouType, transactionID, reportID, Navigation.getActiveRoute(), reportActionID), + ); + }} + style={[styles.moneyRequestMenuItem]} + titleStyle={styles.flex1} + disabled={didConfirm} + interactive={!isReadOnly} + numberOfLinesTitle={2} + /> + + + ), shouldShow: true, isSupplementary: false, diff --git a/src/components/MultiGestureCanvas/usePinchGesture.ts b/src/components/MultiGestureCanvas/usePinchGesture.ts index 6f4cf761a0e4..755f4dfc8603 100644 --- a/src/components/MultiGestureCanvas/usePinchGesture.ts +++ b/src/components/MultiGestureCanvas/usePinchGesture.ts @@ -125,6 +125,8 @@ const usePinchGesture = ({ pinchOrigin.y.set(adjustedFocal.y); }) .onChange((evt) => { + 'worklet'; + // Disable the pinch gesture if one finger is released, // to prevent the content from shaking/jumping if (evt.numberOfPointers !== 2) { diff --git a/src/components/MultiGestureCanvas/useTapGestures.ts b/src/components/MultiGestureCanvas/useTapGestures.ts index a918310d2862..4544a17cbc17 100644 --- a/src/components/MultiGestureCanvas/useTapGestures.ts +++ b/src/components/MultiGestureCanvas/useTapGestures.ts @@ -122,6 +122,8 @@ const useTapGestures = ({ const doubleTapGesture = Gesture.Tap() // The first argument is not used, but must be defined .onTouchesDown((_evt, state) => { + 'worklet'; + if (!shouldDisableTransformationGestures.get()) { return; } @@ -132,6 +134,8 @@ const useTapGestures = ({ .maxDelay(150) .maxDistance(20) .onEnd((evt) => { + 'worklet'; + const triggerScaleChangedEvent = () => { 'worklet'; @@ -153,9 +157,13 @@ const useTapGestures = ({ .numberOfTaps(1) .maxDuration(125) .onBegin(() => { + 'worklet'; + stopAnimation(); }) .onFinalize((_evt, success) => { + 'worklet'; + if (!success || onTap === undefined) { return; } diff --git a/src/components/ReceiptAudit.tsx b/src/components/ReceiptAudit.tsx index 29439911e221..5a56d4028c31 100644 --- a/src/components/ReceiptAudit.tsx +++ b/src/components/ReceiptAudit.tsx @@ -50,7 +50,19 @@ function ReceiptAudit({notes, shouldShowAuditResult}: ReceiptAuditProps) { function ReceiptAuditMessages({notes = []}: {notes?: string[]}) { const styles = useThemeStyles(); - return {notes.length > 0 && notes.map((message) => {message})}; + return ( + + {notes.length > 0 && + notes.map((message) => ( + + {message} + + ))} + + ); } export {ReceiptAuditMessages}; diff --git a/src/components/ReferralProgramCTA.tsx b/src/components/ReferralProgramCTA.tsx index 808df9c4d94d..b2ceac58e43d 100644 --- a/src/components/ReferralProgramCTA.tsx +++ b/src/components/ReferralProgramCTA.tsx @@ -7,6 +7,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import CONST from '@src/CONST'; import Navigation from '@src/libs/Navigation/Navigation'; import ROUTES from '@src/ROUTES'; +import {getButtonRole, getButtonStyle} from './Button/utils'; import Icon from './Icon'; import {Close} from './Icon/Expensicons'; import {PressableWithoutFeedback} from './Pressable'; @@ -52,9 +53,19 @@ function ReferralProgramCTA({referralContentType, style, onDismiss}: ReferralPro onPress={() => { Navigation.navigate(ROUTES.REFERRAL_DETAILS_MODAL.getRoute(referralContentType, Navigation.getActiveRouteWithoutParams())); }} - style={[styles.br2, styles.highlightBG, styles.flexRow, styles.justifyContentBetween, styles.alignItemsCenter, {gap: 10, padding: 10}, styles.pl5, style]} + style={[ + styles.br2, + styles.highlightBG, + styles.flexRow, + styles.justifyContentBetween, + styles.alignItemsCenter, + {gap: 10, padding: 10}, + styles.pl5, + getButtonStyle(styles, true), + style, + ]} accessibilityLabel="referral" - role={CONST.ROLE.BUTTON} + role={getButtonRole(true)} > {translate(`referralProgram.${referralContentType}.buttonText1`)} diff --git a/src/components/ReportActionItem/ReportActionItemImages.tsx b/src/components/ReportActionItem/ReportActionItemImages.tsx index 633dca077070..182b7dc286ef 100644 --- a/src/components/ReportActionItem/ReportActionItemImages.tsx +++ b/src/components/ReportActionItem/ReportActionItemImages.tsx @@ -79,11 +79,11 @@ function ReportActionItemImages({images, size, total, isHovered = false, onPress const shouldShowBorder = shownImages.length > 1 && index < shownImages.length - 1; const borderStyle = shouldShowBorder ? styles.reportActionItemImageBorder : {}; return ( - - + + ControlSelection.unblock()} onLongPress={(event) => showContextMenuForReport(event, contextMenuAnchor, chatReportID, action, checkIfContextMenuActive)} shouldUseHapticsOnLongPress - style={[styles.flexRow, styles.justifyContentBetween, styles.reportPreviewBox]} - role="button" + // This is added to omit console error about nested buttons as its forbidden on web platform + style={[styles.flexRow, styles.justifyContentBetween, styles.reportPreviewBox, getButtonStyle(styles, true)]} + role={getButtonRole(true)} accessibilityLabel={translate('iou.viewDetails')} > diff --git a/src/components/Search/SearchRouter/SearchRouter.tsx b/src/components/Search/SearchRouter/SearchRouter.tsx index fedeb388d3a9..83ee9b9885a8 100644 --- a/src/components/Search/SearchRouter/SearchRouter.tsx +++ b/src/components/Search/SearchRouter/SearchRouter.tsx @@ -1,6 +1,6 @@ import {findFocusedRoute, useNavigationState} from '@react-navigation/native'; import isEqual from 'lodash/isEqual'; -import React, {useCallback, useEffect, useRef, useState} from 'react'; +import React, {forwardRef, useCallback, useEffect, useRef, useState} from 'react'; import {View} from 'react-native'; import type {TextInputProps} from 'react-native'; import {useOnyx} from 'react-native-onyx'; @@ -75,7 +75,7 @@ type SearchRouterProps = { shouldHideInputCaret?: TextInputProps['caretHidden']; }; -function SearchRouter({onRouterClose, shouldHideInputCaret}: SearchRouterProps) { +function SearchRouter({onRouterClose, shouldHideInputCaret}: SearchRouterProps, ref: React.Ref) { const {translate} = useLocalize(); const styles = useThemeStyles(); const [, recentSearchesMetadata] = useOnyx(ONYXKEYS.RECENT_SEARCHES); @@ -304,6 +304,7 @@ function SearchRouter({onRouterClose, shouldHideInputCaret}: SearchRouterProps) {shouldUseNarrowLayout && ( ({ disabled={isDisabled && !item.isSelected} interactive={item.isInteractive} accessibilityLabel={item.text ?? ''} - role={CONST.ROLE.BUTTON} + role={getButtonRole(true)} hoverDimmingValue={1} hoverStyle={[!item.isDisabled && item.isInteractive !== false && styles.hoveredComponentBG, hoverStyle]} dataSet={{[CONST.SELECTION_SCRAPER_HIDDEN_ELEMENT]: true, [CONST.INNER_BOX_SHADOW_ELEMENT]: shouldShowBlueBorderOnFocus}} @@ -103,6 +104,7 @@ function BaseListItem({ style={[ pressableStyle, isFocused && StyleUtils.getItemBackgroundColorStyle(!!item.isSelected, !!isFocused, !!item.isDisabled, theme.activeComponentBG, theme.hoverComponentBG), + getButtonStyle(styles, true), ]} onFocus={onFocus} onMouseLeave={handleMouseLeave} diff --git a/src/components/SelectionList/Search/ActionCell.tsx b/src/components/SelectionList/Search/ActionCell.tsx index 5b96771b7dd6..dca9f529e7f0 100644 --- a/src/components/SelectionList/Search/ActionCell.tsx +++ b/src/components/SelectionList/Search/ActionCell.tsx @@ -89,6 +89,7 @@ function ActionCell({ icon={!isChildListItem && action === CONST.SEARCH.ACTION_TYPES.REVIEW ? Expensicons.DotIndicator : undefined} iconFill={theme.danger} iconHoverFill={theme.dangerHover} + isNested /> ) : null; } @@ -102,6 +103,7 @@ function ActionCell({ isLoading={isLoading} success isDisabled={isOffline} + isNested /> ); } diff --git a/src/components/SelectionList/Search/ExpenseItemHeaderNarrow.tsx b/src/components/SelectionList/Search/ExpenseItemHeaderNarrow.tsx index d59d85c04957..341d46d8bda0 100644 --- a/src/components/SelectionList/Search/ExpenseItemHeaderNarrow.tsx +++ b/src/components/SelectionList/Search/ExpenseItemHeaderNarrow.tsx @@ -1,6 +1,7 @@ import React, {memo} from 'react'; import {View} from 'react-native'; import type {StyleProp, ViewStyle} from 'react-native'; +import {getButtonRole} from '@components/Button/utils'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; import {PressableWithFeedback} from '@components/Pressable'; @@ -9,7 +10,6 @@ import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import {isCorrectSearchUserName} from '@libs/SearchUIUtils'; import variables from '@styles/variables'; -import CONST from '@src/CONST'; import type {SearchPersonalDetails, SearchTransactionAction} from '@src/types/onyx/SearchResults'; import ActionCell from './ActionCell'; import UserInfoCell from './UserInfoCell'; @@ -60,7 +60,7 @@ function ExpenseItemHeaderNarrow({ {!!canSelectMultiple && ( handleCheckboxPress?.()} style={[styles.cursorUnset, StyleUtils.getCheckboxPressableStyle(), isDisabledCheckbox && styles.cursorDisabled, styles.mr1]} diff --git a/src/components/SelectionList/Search/TransactionListItemRow.tsx b/src/components/SelectionList/Search/TransactionListItemRow.tsx index c149c29b7af5..abd29640f571 100644 --- a/src/components/SelectionList/Search/TransactionListItemRow.tsx +++ b/src/components/SelectionList/Search/TransactionListItemRow.tsx @@ -2,6 +2,7 @@ import {Str} from 'expensify-common'; import React from 'react'; import type {StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; +import {getButtonRole, getButtonStyle} from '@components/Button/utils'; import Checkbox from '@components/Checkbox'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; @@ -298,10 +299,10 @@ function TransactionListItemRow({ {canSelectMultiple && !!shouldShowTransactionCheckbox && ( {!!item.isSelected && ( diff --git a/src/components/TextBlock.tsx b/src/components/TextBlock.tsx index 8b036f42f4cc..c26bcc029c2b 100644 --- a/src/components/TextBlock.tsx +++ b/src/components/TextBlock.tsx @@ -26,6 +26,7 @@ function TextBlock({color, textStyles, text}: TextBlockProps) { {word} diff --git a/src/components/ThreeDotsMenu/index.tsx b/src/components/ThreeDotsMenu/index.tsx index 5bf8e52642f1..6dc44be378e5 100644 --- a/src/components/ThreeDotsMenu/index.tsx +++ b/src/components/ThreeDotsMenu/index.tsx @@ -1,6 +1,7 @@ import React, {useEffect, useRef, useState} from 'react'; import {View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; +import {getButtonRole, getButtonStyle} from '@components/Button/utils'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; import PopoverMenu from '@components/PopoverMenu'; @@ -34,6 +35,7 @@ function ThreeDotsMenu({ hideProductTrainingTooltip, renderProductTrainingTooltipContent, shouldShowProductTrainingTooltip = false, + isNested = false, }: ThreeDotsMenuProps) { const [modal] = useOnyx(ONYXKEYS.MODAL); @@ -104,8 +106,8 @@ function ThreeDotsMenu({ e.preventDefault(); }} ref={buttonRef} - style={[styles.touchableButtonImage, iconStyles]} - role={CONST.ROLE.BUTTON} + style={[styles.touchableButtonImage, iconStyles, getButtonStyle(styles, isNested)]} + role={getButtonRole(isNested)} accessibilityLabel={translate(iconTooltip)} > ; diff --git a/src/libs/actions/Link.ts b/src/libs/actions/Link.ts index cee639f4c4a3..297ad378527a 100644 --- a/src/libs/actions/Link.ts +++ b/src/libs/actions/Link.ts @@ -12,7 +12,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; -import * as Session from './Session'; +import {canAnonymousUserAccessRoute, isAnonymousUser, signOutAndRedirectToSignIn} from './Session'; let isNetworkOffline = false; Onyx.connect({ @@ -26,7 +26,7 @@ Onyx.connect({ key: ONYXKEYS.SESSION, callback: (value) => { currentUserEmail = value?.email ?? ''; - currentUserAccountID = value?.accountID ?? -1; + currentUserAccountID = value?.accountID ?? CONST.DEFAULT_NUMBER_ID; }, }); @@ -138,6 +138,9 @@ function openTravelDotLink(policyID: OnyxEntry, postLoginPath?: string) } function getInternalNewExpensifyPath(href: string) { + if (!href) { + return ''; + } const attrPath = Url.getPathFromURL(href); return (Url.hasSameExpensifyOrigin(href, CONST.NEW_EXPENSIFY_URL) || Url.hasSameExpensifyOrigin(href, CONST.STAGING_NEW_EXPENSIFY_URL) || href.startsWith(CONST.DEV_NEW_EXPENSIFY_URL)) && !CONST.PATHS_TO_TREAT_AS_EXTERNAL.find((path) => attrPath.startsWith(path)) @@ -146,6 +149,10 @@ function getInternalNewExpensifyPath(href: string) { } function getInternalExpensifyPath(href: string) { + if (!href) { + return ''; + } + const attrPath = Url.getPathFromURL(href); const hasExpensifyOrigin = Url.hasSameExpensifyOrigin(href, CONFIG.EXPENSIFY.EXPENSIFY_URL) || Url.hasSameExpensifyOrigin(href, CONFIG.EXPENSIFY.STAGING_API_ROOT); if (!hasExpensifyOrigin || attrPath.startsWith(CONFIG.EXPENSIFY.CONCIERGE_URL_PATHNAME) || attrPath.startsWith(CONFIG.EXPENSIFY.DEVPORTAL_URL_PATHNAME)) { @@ -168,7 +175,7 @@ function openLink(href: string, environmentURL: string, isAttachment = false) { // the reportID is extracted from the URL and then opened as an internal link, taking the user straight to the chat in the same tab. if (hasExpensifyOrigin && href.indexOf('newdotreport?reportID=') > -1) { const reportID = href.split('newdotreport?reportID=').pop(); - const reportRoute = ROUTES.REPORT_WITH_ID.getRoute(reportID ?? '-1'); + const reportRoute = ROUTES.REPORT_WITH_ID.getRoute(reportID); Navigation.navigate(reportRoute); return; } @@ -176,8 +183,8 @@ function openLink(href: string, environmentURL: string, isAttachment = false) { // If we are handling a New Expensify link then we will assume this should be opened by the app internally. This ensures that the links are opened internally via react-navigation // instead of in a new tab or with a page refresh (which is the default behavior of an anchor tag) if (internalNewExpensifyPath && hasSameOrigin) { - if (Session.isAnonymousUser() && !Session.canAnonymousUserAccessRoute(internalNewExpensifyPath)) { - Session.signOutAndRedirectToSignIn(); + if (isAnonymousUser() && !canAnonymousUserAccessRoute(internalNewExpensifyPath)) { + signOutAndRedirectToSignIn(); return; } Navigation.navigate(internalNewExpensifyPath as Route); diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx index 54ab7b812cd9..8e2a8c6cde48 100644 --- a/src/pages/Search/AdvancedSearchFilters.tsx +++ b/src/pages/Search/AdvancedSearchFilters.tsx @@ -519,7 +519,8 @@ function AdvancedSearchFilters() { {filters.map((section, index) => { return ( - <> + // eslint-disable-next-line react/no-array-index-key + {index !== 0 && ( ); })} - + ); })} diff --git a/src/pages/workspace/WorkspacesListRow.tsx b/src/pages/workspace/WorkspacesListRow.tsx index 5e182bf12ffa..64f36589dfbb 100644 --- a/src/pages/workspace/WorkspacesListRow.tsx +++ b/src/pages/workspace/WorkspacesListRow.tsx @@ -187,6 +187,7 @@ function WorkspacesListRow({ anchorAlignment={{horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.RIGHT, vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP}} shouldOverlay disabled={shouldDisableThreeDotsMenu} + isNested />