From 225dadebc4d5fe81e60d2e5dedcc81463d7eedba Mon Sep 17 00:00:00 2001 From: GCyganek Date: Fri, 3 Oct 2025 16:16:01 +0200 Subject: [PATCH 1/4] Change SelectionList in IOURequestStepSendFrom --- .../SelectionList/ListItem/UserListItem.tsx | 195 ++++++++++++++++++ .../SelectionList/ListItem/types.ts | 4 + .../request/step/IOURequestStepSendFrom.tsx | 10 +- 3 files changed, 204 insertions(+), 5 deletions(-) create mode 100644 src/components/SelectionList/ListItem/UserListItem.tsx diff --git a/src/components/SelectionList/ListItem/UserListItem.tsx b/src/components/SelectionList/ListItem/UserListItem.tsx new file mode 100644 index 0000000000000..ddba607c5f07d --- /dev/null +++ b/src/components/SelectionList/ListItem/UserListItem.tsx @@ -0,0 +1,195 @@ +import {Str} from 'expensify-common'; +import React, {useCallback} from 'react'; +import {View} from 'react-native'; +import Icon from '@components/Icon'; +import * as Expensicons from '@components/Icon/Expensicons'; +import PressableWithFeedback from '@components/Pressable/PressableWithFeedback'; +import ReportActionAvatars from '@components/ReportActionAvatars'; +import Text from '@components/Text'; +import TextWithTooltip from '@components/TextWithTooltip'; +import useLocalize from '@hooks/useLocalize'; +import useOnyx from '@hooks/useOnyx'; +import useStyleUtils from '@hooks/useStyleUtils'; +import useTheme from '@hooks/useTheme'; +import useThemeStyles from '@hooks/useThemeStyles'; +import getButtonState from '@libs/getButtonState'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import BaseListItem from './BaseListItem'; +import type {ListItem, UserListItemProps} from './types'; + +function UserListItem({ + item, + isFocused, + showTooltip, + isDisabled, + canSelectMultiple, + onSelectRow, + onCheckboxPress, + onDismissError, + shouldPreventEnterKeySubmit, + rightHandSideComponent, + onFocus, + shouldSyncFocus, + wrapperStyle, + pressableStyle, + shouldUseDefaultRightHandSideCheckmark, + forwardedFSClass, +}: UserListItemProps) { + const styles = useThemeStyles(); + const theme = useTheme(); + const StyleUtils = useStyleUtils(); + const {translate} = useLocalize(); + + const focusedBackgroundColor = styles.sidebarLinkActive.backgroundColor; + const subscriptAvatarBorderColor = isFocused ? focusedBackgroundColor : theme.sidebar; + const hoveredBackgroundColor = !!styles.sidebarLinkHover && 'backgroundColor' in styles.sidebarLinkHover ? styles.sidebarLinkHover.backgroundColor : theme.sidebar; + + const handleCheckboxPress = useCallback(() => { + if (onCheckboxPress) { + onCheckboxPress(item); + } else { + onSelectRow(item); + } + }, [item, onCheckboxPress, onSelectRow]); + + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + const [isReportInOnyx] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${item.reportID}`, { + canBeMissing: true, + selector: (report) => !!report, + }); + + const reportExists = isReportInOnyx && !!item.reportID; + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + const itemAccountID = Number(item.accountID || item.icons?.at(1)?.id) || 0; + + const isThereOnlyWorkspaceIcon = item.icons?.length === 1 && item.icons?.at(0)?.type === CONST.ICON_TYPE_WORKSPACE; + const shouldUseIconPolicyID = !item.reportID && !item.accountID && !item.policyID; + const policyID = isThereOnlyWorkspaceIcon && shouldUseIconPolicyID ? String(item.icons?.at(0)?.id) : item.policyID; + + return ( + + {translate('workspace.people.invitedBySecondaryLogin', {secondaryLogin: item.invitedSecondaryLogin})} + + ) : undefined + } + keyForList={item.keyForList} + onFocus={onFocus} + shouldSyncFocus={shouldSyncFocus} + > + {(hovered?: boolean) => ( + <> + {!shouldUseDefaultRightHandSideCheckmark && !!canSelectMultiple && ( + + + {!!item.isSelected && ( + + )} + + + )} + {(!!reportExists || !!itemAccountID || !!policyID) && ( + + )} + + + {!!item.alternateText && ( + + )} + + {!!item.rightElement && item.rightElement} + {!!item.shouldShowRightIcon && ( + + + + )} + {!!shouldUseDefaultRightHandSideCheckmark && !!canSelectMultiple && ( + + + {!!item.isSelected && ( + + )} + + + )} + + )} + + ); +} + +UserListItem.displayName = 'UserListItem'; + +export default UserListItem; diff --git a/src/components/SelectionList/ListItem/types.ts b/src/components/SelectionList/ListItem/types.ts index b11dfc1c6028d..f04d928b9106f 100644 --- a/src/components/SelectionList/ListItem/types.ts +++ b/src/components/SelectionList/ListItem/types.ts @@ -1,6 +1,7 @@ import type {ReactElement, ReactNode} from 'react'; import type {AccessibilityState, NativeSyntheticEvent, StyleProp, TargetedEvent, TextStyle, ViewStyle} from 'react-native'; import type {AnimatedStyle} from 'react-native-reanimated'; +import type {ForwardedFSClassProps} from '@libs/Fullstory/types'; import type {BrickRoad} from '@libs/WorkspacesSettingsUtils'; // eslint-disable-next-line no-restricted-imports import type CursorStyles from '@styles/utils/cursor/types'; @@ -256,6 +257,8 @@ type SingleSelectListItemProps = ListItemProps; type MultiSelectListItemProps = ListItemProps; +type UserListItemProps = ListItemProps & ForwardedFSClassProps; + export type { BaseListItemProps, ExtendedTargetedEvent, @@ -266,4 +269,5 @@ export type { ValidListItem, SingleSelectListItemProps, MultiSelectListItemProps, + UserListItemProps, }; diff --git a/src/pages/iou/request/step/IOURequestStepSendFrom.tsx b/src/pages/iou/request/step/IOURequestStepSendFrom.tsx index f60f4568d8c1b..af70996ee0c14 100644 --- a/src/pages/iou/request/step/IOURequestStepSendFrom.tsx +++ b/src/pages/iou/request/step/IOURequestStepSendFrom.tsx @@ -1,9 +1,9 @@ import {emailSelector} from '@selectors/Session'; import React, {useMemo} from 'react'; import * as Expensicons from '@components/Icon/Expensicons'; -import SelectionList from '@components/SelectionListWithSections'; -import type {ListItem} from '@components/SelectionListWithSections/types'; -import UserListItem from '@components/SelectionListWithSections/UserListItem'; +import SelectionList from '@components/SelectionList'; +import UserListItem from '@components/SelectionList/ListItem/UserListItem'; +import type {ListItem} from '@components/SelectionList/types'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import Navigation from '@libs/Navigation/Navigation'; @@ -89,11 +89,11 @@ function IOURequestStepSendFrom({route, transaction}: IOURequestStepSendFromProp includeSafeAreaPaddingBottom > ); From 22d012dc60c2fc335adb369a6dad7612b5a0cac2 Mon Sep 17 00:00:00 2001 From: GCyganek Date: Mon, 6 Oct 2025 14:24:00 +0200 Subject: [PATCH 2/4] Restore Workspaces label for SelectionList --- src/pages/iou/request/step/IOURequestStepSendFrom.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/pages/iou/request/step/IOURequestStepSendFrom.tsx b/src/pages/iou/request/step/IOURequestStepSendFrom.tsx index af70996ee0c14..df9dec80dc788 100644 --- a/src/pages/iou/request/step/IOURequestStepSendFrom.tsx +++ b/src/pages/iou/request/step/IOURequestStepSendFrom.tsx @@ -1,11 +1,14 @@ import {emailSelector} from '@selectors/Session'; import React, {useMemo} from 'react'; +import {View} from 'react-native'; import * as Expensicons from '@components/Icon/Expensicons'; import SelectionList from '@components/SelectionList'; import UserListItem from '@components/SelectionList/ListItem/UserListItem'; import type {ListItem} from '@components/SelectionList/types'; +import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; +import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; import {canSendInvoiceFromWorkspace, getActiveAdminWorkspaces, sortWorkspacesBySelected} from '@libs/PolicyUtils'; import {getDefaultWorkspaceAvatar} from '@libs/ReportUtils'; @@ -27,6 +30,7 @@ type IOURequestStepSendFromProps = WithWritableReportOrNotFoundProps; function IOURequestStepSendFrom({route, transaction}: IOURequestStepSendFromProps) { + const styles = useThemeStyles(); const {translate, localeCompare} = useLocalize(); const {transactionID, backTo} = route.params; const [currentUserLogin] = useOnyx(ONYXKEYS.SESSION, {selector: emailSelector, canBeMissing: false}); @@ -88,6 +92,9 @@ function IOURequestStepSendFrom({route, transaction}: IOURequestStepSendFromProp testID={IOURequestStepSendFrom.displayName} includeSafeAreaPaddingBottom > + + {translate('common.workspaces')} + Date: Mon, 6 Oct 2025 17:31:41 +0200 Subject: [PATCH 3/4] Revert: Restore Workspaces label for SelectionList --- src/pages/iou/request/step/IOURequestStepSendFrom.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/pages/iou/request/step/IOURequestStepSendFrom.tsx b/src/pages/iou/request/step/IOURequestStepSendFrom.tsx index df9dec80dc788..27994f423bb49 100644 --- a/src/pages/iou/request/step/IOURequestStepSendFrom.tsx +++ b/src/pages/iou/request/step/IOURequestStepSendFrom.tsx @@ -92,9 +92,6 @@ function IOURequestStepSendFrom({route, transaction}: IOURequestStepSendFromProp testID={IOURequestStepSendFrom.displayName} includeSafeAreaPaddingBottom > - - {translate('common.workspaces')} - Date: Mon, 6 Oct 2025 18:00:52 +0200 Subject: [PATCH 4/4] Fix linter error --- src/pages/iou/request/step/IOURequestStepSendFrom.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/pages/iou/request/step/IOURequestStepSendFrom.tsx b/src/pages/iou/request/step/IOURequestStepSendFrom.tsx index 27994f423bb49..af70996ee0c14 100644 --- a/src/pages/iou/request/step/IOURequestStepSendFrom.tsx +++ b/src/pages/iou/request/step/IOURequestStepSendFrom.tsx @@ -1,14 +1,11 @@ import {emailSelector} from '@selectors/Session'; import React, {useMemo} from 'react'; -import {View} from 'react-native'; import * as Expensicons from '@components/Icon/Expensicons'; import SelectionList from '@components/SelectionList'; import UserListItem from '@components/SelectionList/ListItem/UserListItem'; import type {ListItem} from '@components/SelectionList/types'; -import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; -import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; import {canSendInvoiceFromWorkspace, getActiveAdminWorkspaces, sortWorkspacesBySelected} from '@libs/PolicyUtils'; import {getDefaultWorkspaceAvatar} from '@libs/ReportUtils'; @@ -30,7 +27,6 @@ type IOURequestStepSendFromProps = WithWritableReportOrNotFoundProps; function IOURequestStepSendFrom({route, transaction}: IOURequestStepSendFromProps) { - const styles = useThemeStyles(); const {translate, localeCompare} = useLocalize(); const {transactionID, backTo} = route.params; const [currentUserLogin] = useOnyx(ONYXKEYS.SESSION, {selector: emailSelector, canBeMissing: false});