diff --git a/src/components/SelectionList/BaseSelectionList.tsx b/src/components/SelectionList/BaseSelectionList.tsx index 66d648f1b472..0e12e993cc79 100644 --- a/src/components/SelectionList/BaseSelectionList.tsx +++ b/src/components/SelectionList/BaseSelectionList.tsx @@ -487,7 +487,8 @@ function BaseSelectionList( const renderItem = ({item, index, section}: SectionListRenderItemInfo>) => { const normalizedIndex = index + (section?.indexOffset ?? 0); const isDisabled = !!section.isDisabled || item.isDisabled; - const isItemFocused = (!isDisabled || item.isSelected) && (focusedIndex === normalizedIndex || itemsToHighlight?.has(item.keyForList ?? '')); + const isItemFocused = (!isDisabled || item.isSelected) && focusedIndex === normalizedIndex; + const isItemHighlighted = !!itemsToHighlight?.has(item.keyForList ?? ''); // We only create tooltips for the first 10 users or so since some reports have hundreds of users, causing performance to degrade. const showTooltip = shouldShowTooltips && normalizedIndex < 10; @@ -495,7 +496,10 @@ function BaseSelectionList( onItemLayout(event, item?.keyForList)}> ( * @param timeout - The timeout in milliseconds before removing the highlight. */ const scrollAndHighlightItem = useCallback( - (items: string[], timeout: number) => { + (items: string[]) => { const newItemsToHighlight = new Set(); items.forEach((item) => { newItemsToHighlight.add(item); }); const index = flattenedSections.allOptions.findIndex((option) => newItemsToHighlight.has(option.keyForList ?? '')); - updateAndScrollToFocusedIndex(index); + scrollToIndex(index); setItemsToHighlight(newItemsToHighlight); if (itemFocusTimeoutRef.current) { clearTimeout(itemFocusTimeoutRef.current); } + const duration = + CONST.ANIMATED_HIGHLIGHT_ENTRY_DELAY + + CONST.ANIMATED_HIGHLIGHT_ENTRY_DURATION + + CONST.ANIMATED_HIGHLIGHT_START_DELAY + + CONST.ANIMATED_HIGHLIGHT_START_DURATION + + CONST.ANIMATED_HIGHLIGHT_END_DELAY + + CONST.ANIMATED_HIGHLIGHT_END_DURATION; itemFocusTimeoutRef.current = setTimeout(() => { - setFocusedIndex(-1); setItemsToHighlight(null); - }, timeout); + }, duration); }, - [flattenedSections.allOptions, setFocusedIndex, updateAndScrollToFocusedIndex], + [flattenedSections.allOptions, scrollToIndex], ); /** diff --git a/src/components/SelectionList/TableListItem.tsx b/src/components/SelectionList/TableListItem.tsx index 0900e49f43ce..8b27ee8a20f8 100644 --- a/src/components/SelectionList/TableListItem.tsx +++ b/src/components/SelectionList/TableListItem.tsx @@ -5,6 +5,7 @@ import * as Expensicons from '@components/Icon/Expensicons'; import MultipleAvatars from '@components/MultipleAvatars'; import PressableWithFeedback from '@components/Pressable/PressableWithFeedback'; import TextWithTooltip from '@components/TextWithTooltip'; +import useAnimatedHighlightStyle from '@hooks/useAnimatedHighlightStyle'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -30,6 +31,13 @@ function TableListItem({ const theme = useTheme(); const StyleUtils = useStyleUtils(); + const animatedHighlightStyle = useAnimatedHighlightStyle({ + borderRadius: styles.selectionListPressableItemWrapper.borderRadius, + shouldHighlight: !!item.shouldAnimateInHighlight, + highlightColor: theme.messageHighlightBG, + backgroundColor: theme.highlightBG, + }); + const focusedBackgroundColor = styles.sidebarLinkActive.backgroundColor; const hoveredBackgroundColor = styles.sidebarLinkHover?.backgroundColor ? styles.sidebarLinkHover.backgroundColor : theme.sidebar; @@ -44,7 +52,17 @@ function TableListItem({ return ( = Partial & { } & TRightHandSideComponent; type SelectionListHandle = { - scrollAndHighlightItem?: (items: string[], timeout: number) => void; + scrollAndHighlightItem?: (items: string[]) => void; clearInputAfterSelect?: () => void; scrollToIndex: (index: number, animated?: boolean) => void; updateAndScrollToFocusedIndex: (newFocusedIndex: number) => void; diff --git a/src/pages/workspace/WorkspaceInvitePage.tsx b/src/pages/workspace/WorkspaceInvitePage.tsx index ac3d25c015a1..7fef254d3ca9 100644 --- a/src/pages/workspace/WorkspaceInvitePage.tsx +++ b/src/pages/workspace/WorkspaceInvitePage.tsx @@ -1,4 +1,3 @@ -import {useNavigation} from '@react-navigation/native'; import type {StackScreenProps} from '@react-navigation/stack'; import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; import type {SectionListData} from 'react-native'; @@ -16,7 +15,6 @@ import useDebouncedState from '@hooks/useDebouncedState'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useThemeStyles from '@hooks/useThemeStyles'; -import * as FormActions from '@libs/actions/FormActions'; import * as ReportActions from '@libs/actions/Report'; import {READ_COMMANDS} from '@libs/API/types'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; @@ -49,7 +47,6 @@ type WorkspaceInvitePageProps = WithPolicyAndFullscreenLoadingProps & WithNaviga function WorkspaceInvitePage({route, policy}: WorkspaceInvitePageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); - const navigation = useNavigation(); const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState(''); const [selectedOptions, setSelectedOptions] = useState([]); const [personalDetails, setPersonalDetails] = useState([]); @@ -68,15 +65,6 @@ function WorkspaceInvitePage({route, policy}: WorkspaceInvitePageProps) { shouldInitialize: didScreenTransitionEnd, }); - useEffect(() => { - const unsubscribe = navigation.addListener('beforeRemove', () => { - Member.setWorkspaceInviteMembersDraft(route.params.policyID, {}); - FormActions.clearDraftValues(ONYXKEYS.FORMS.WORKSPACE_INVITE_MESSAGE_FORM); - }); - - return unsubscribe; - }, [navigation, route.params.policyID]); - useEffect(() => { Policy.clearErrors(route.params.policyID); openWorkspaceInvitePage(); diff --git a/src/pages/workspace/WorkspaceMembersPage.tsx b/src/pages/workspace/WorkspaceMembersPage.tsx index cb914591a59d..6034e7d493cd 100644 --- a/src/pages/workspace/WorkspaceMembersPage.tsx +++ b/src/pages/workspace/WorkspaceMembersPage.tsx @@ -195,10 +195,16 @@ function WorkspaceMembersPage({personalDetails, route, policy, currentUserPerson getWorkspaceMembers(); }, [isOffline, prevIsOffline, getWorkspaceMembers]); + const clearInviteDraft = useCallback(() => { + Member.setWorkspaceInviteMembersDraft(route.params.policyID, {}); + FormActions.clearDraftValues(ONYXKEYS.FORMS.WORKSPACE_INVITE_MESSAGE_FORM); + }, [route.params.policyID]); + /** * Open the modal to invite a user */ const inviteUser = () => { + clearInviteDraft(); Navigation.navigate(ROUTES.WORKSPACE_INVITE.getRoute(route.params.policyID)); }; @@ -416,10 +422,9 @@ function WorkspaceMembersPage({personalDetails, route, policy, currentUserPerson return; } const invitedEmails = Object.values(invitedEmailsToAccountIDsDraft).map(String); - selectionListRef.current?.scrollAndHighlightItem?.(invitedEmails, 1500); - Member.setWorkspaceInviteMembersDraft(route.params.policyID, {}); - FormActions.clearDraftValues(ONYXKEYS.FORMS.WORKSPACE_INVITE_MESSAGE_FORM); - }, [invitedEmailsToAccountIDsDraft, route.params.policyID, isFocused, accountIDs, prevAccountIDs]); + selectionListRef.current?.scrollAndHighlightItem?.(invitedEmails); + clearInviteDraft(); + }, [invitedEmailsToAccountIDsDraft, isFocused, accountIDs, prevAccountIDs, clearInviteDraft]); const getHeaderMessage = () => { if (isOfflineAndNoMemberDataAvailable) {