From 1b489fff35b8bb9047d3c0faf3fcca72d9ac373a Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Fri, 2 Feb 2024 15:16:52 +0200 Subject: [PATCH] Revert "20354 task assignees list refactor" --- src/components/OnyxProvider.tsx | 6 +- .../withCurrentUserPersonalDetails.tsx | 35 +++- src/hooks/useCurrentUserPersonalDetails.ts | 21 --- src/pages/tasks/TaskAssigneeSelectorModal.js | 175 +++++++++++------- 4 files changed, 133 insertions(+), 104 deletions(-) delete mode 100644 src/hooks/useCurrentUserPersonalDetails.ts diff --git a/src/components/OnyxProvider.tsx b/src/components/OnyxProvider.tsx index d14aec90fa10..124f3558df90 100644 --- a/src/components/OnyxProvider.tsx +++ b/src/components/OnyxProvider.tsx @@ -10,12 +10,11 @@ const [withPersonalDetails, PersonalDetailsProvider, , usePersonalDetails] = cre const [withCurrentDate, CurrentDateProvider] = createOnyxContext(ONYXKEYS.CURRENT_DATE); const [withReportActionsDrafts, ReportActionsDraftsProvider] = createOnyxContext(ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS); const [withBlockedFromConcierge, BlockedFromConciergeProvider] = createOnyxContext(ONYXKEYS.NVP_BLOCKED_FROM_CONCIERGE); -const [withBetas, BetasProvider, BetasContext, useBetas] = createOnyxContext(ONYXKEYS.BETAS); +const [withBetas, BetasProvider, BetasContext] = createOnyxContext(ONYXKEYS.BETAS); const [withReportCommentDrafts, ReportCommentDraftsProvider] = createOnyxContext(ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT); const [withPreferredTheme, PreferredThemeProvider, PreferredThemeContext] = createOnyxContext(ONYXKEYS.PREFERRED_THEME); const [withFrequentlyUsedEmojis, FrequentlyUsedEmojisProvider, , useFrequentlyUsedEmojis] = createOnyxContext(ONYXKEYS.FREQUENTLY_USED_EMOJIS); const [withPreferredEmojiSkinTone, PreferredEmojiSkinToneProvider, PreferredEmojiSkinToneContext] = createOnyxContext(ONYXKEYS.PREFERRED_EMOJI_SKIN_TONE); -const [, SessionProvider, , useSession] = createOnyxContext(ONYXKEYS.SESSION); type OnyxProviderProps = { /** Rendered child component */ @@ -36,7 +35,6 @@ function OnyxProvider(props: OnyxProviderProps) { PreferredThemeProvider, FrequentlyUsedEmojisProvider, PreferredEmojiSkinToneProvider, - SessionProvider, ]} > {props.children} @@ -61,10 +59,8 @@ export { withReportCommentDrafts, withPreferredTheme, PreferredThemeContext, - useBetas, withFrequentlyUsedEmojis, useFrequentlyUsedEmojis, withPreferredEmojiSkinTone, PreferredEmojiSkinToneContext, - useSession, }; diff --git a/src/components/withCurrentUserPersonalDetails.tsx b/src/components/withCurrentUserPersonalDetails.tsx index 313bcad74f35..9406c8634c1b 100644 --- a/src/components/withCurrentUserPersonalDetails.tsx +++ b/src/components/withCurrentUserPersonalDetails.tsx @@ -1,17 +1,26 @@ import type {ComponentType, ForwardedRef, RefAttributes} from 'react'; -import React from 'react'; -import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; +import React, {useMemo} from 'react'; +import type {OnyxEntry} from 'react-native-onyx'; +import {withOnyx} from 'react-native-onyx'; import getComponentDisplayName from '@libs/getComponentDisplayName'; import personalDetailsPropType from '@pages/personalDetailsPropType'; -import type {PersonalDetails} from '@src/types/onyx'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type {PersonalDetails, Session} from '@src/types/onyx'; +import {usePersonalDetails} from './OnyxProvider'; type CurrentUserPersonalDetails = PersonalDetails | Record; +type OnyxProps = { + /** Session of the current user */ + session: OnyxEntry; +}; + type HOCProps = { currentUserPersonalDetails: CurrentUserPersonalDetails; }; -type WithCurrentUserPersonalDetailsProps = HOCProps; +type WithCurrentUserPersonalDetailsProps = OnyxProps & HOCProps; // TODO: remove when all components that use it will be migrated to TS const withCurrentUserPersonalDetailsPropTypes = { @@ -24,9 +33,15 @@ const withCurrentUserPersonalDetailsDefaultProps: HOCProps = { export default function ( WrappedComponent: ComponentType>, -): ComponentType & RefAttributes> { +): ComponentType & RefAttributes, keyof OnyxProps>> { function WithCurrentUserPersonalDetails(props: Omit, ref: ForwardedRef) { - const currentUserPersonalDetails = useCurrentUserPersonalDetails(); + const personalDetails = usePersonalDetails() ?? CONST.EMPTY_OBJECT; + const accountID = props.session?.accountID ?? 0; + const accountPersonalDetails = personalDetails?.[accountID]; + const currentUserPersonalDetails: CurrentUserPersonalDetails = useMemo( + () => (accountPersonalDetails ? {...accountPersonalDetails, accountID} : {}) as CurrentUserPersonalDetails, + [accountPersonalDetails, accountID], + ); return ( & RefAttributes, OnyxProps>({ + session: { + key: ONYXKEYS.SESSION, + }, + })(withCurrentUserPersonalDetails); } export {withCurrentUserPersonalDetailsPropTypes, withCurrentUserPersonalDetailsDefaultProps}; diff --git a/src/hooks/useCurrentUserPersonalDetails.ts b/src/hooks/useCurrentUserPersonalDetails.ts deleted file mode 100644 index da3c2b18bd83..000000000000 --- a/src/hooks/useCurrentUserPersonalDetails.ts +++ /dev/null @@ -1,21 +0,0 @@ -import {useMemo} from 'react'; -import {usePersonalDetails, useSession} from '@components/OnyxProvider'; -import CONST from '@src/CONST'; -import type {PersonalDetails} from '@src/types/onyx'; - -type CurrentUserPersonalDetails = PersonalDetails | Record; - -function useCurrentUserPersonalDetails() { - const session = useSession(); - const personalDetails = usePersonalDetails() ?? CONST.EMPTY_OBJECT; - const accountID = session?.accountID ?? 0; - const accountPersonalDetails = personalDetails?.[accountID]; - const currentUserPersonalDetails: CurrentUserPersonalDetails = useMemo( - () => (accountPersonalDetails ? {...accountPersonalDetails, accountID} : {}) as CurrentUserPersonalDetails, - [accountPersonalDetails, accountID], - ); - - return currentUserPersonalDetails; -} - -export default useCurrentUserPersonalDetails; diff --git a/src/pages/tasks/TaskAssigneeSelectorModal.js b/src/pages/tasks/TaskAssigneeSelectorModal.js index 0619fe1abf15..f3627a9bd04d 100644 --- a/src/pages/tasks/TaskAssigneeSelectorModal.js +++ b/src/pages/tasks/TaskAssigneeSelectorModal.js @@ -1,19 +1,18 @@ /* eslint-disable es/no-optional-chaining */ -import {useRoute} from '@react-navigation/native'; import lodashGet from 'lodash/get'; -import lodashPick from 'lodash/pick'; import PropTypes from 'prop-types'; -import React, {useCallback, useMemo, useState} from 'react'; +import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; +import _ from 'underscore'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import {useBetas, usePersonalDetails, useSession} from '@components/OnyxProvider'; +import {usePersonalDetails} from '@components/OnyxProvider'; +import OptionsSelector from '@components/OptionsSelector'; import ScreenWrapper from '@components/ScreenWrapper'; -import SelectionList from '@components/SelectionList'; -import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; -import useDebouncedState from '@hooks/useDebouncedState'; -import useLocalize from '@hooks/useLocalize'; +import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails'; +import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; +import useAutoFocusInput from '@hooks/useAutoFocusInput'; import useThemeStyles from '@hooks/useThemeStyles'; import compose from '@libs/compose'; import Navigation from '@libs/Navigation/Navigation'; @@ -26,9 +25,29 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; const propTypes = { + /** Beta features list */ + betas: PropTypes.arrayOf(PropTypes.string), + /** All reports shared with the user */ reports: PropTypes.objectOf(reportPropTypes), + /** URL Route params */ + route: PropTypes.shape({ + /** Params from the URL path */ + params: PropTypes.shape({ + /** reportID passed via route: /r/:reportID/title */ + reportID: PropTypes.string, + }), + }), + + // /** The report currently being looked at */ + // report: reportPropTypes.isRequired, + + /** Current user session */ + session: PropTypes.shape({ + email: PropTypes.string.isRequired, + }), + /** Grab the Share destination of the Task */ task: PropTypes.shape({ /** Share destination of the Task */ @@ -43,26 +62,38 @@ const propTypes = { /** The role of current user */ role: PropTypes.string, }), + + ...withLocalizePropTypes, }; const defaultProps = { + betas: [], reports: {}, + session: {}, + route: {}, task: {}, rootParentReportPolicy: {}, }; -function useOptions({reports}) { +function TaskAssigneeSelectorModal(props) { + const styles = useThemeStyles(); + const [searchValue, setSearchValue] = useState(''); + const [headerMessage, setHeaderMessage] = useState(''); + const [filteredRecentReports, setFilteredRecentReports] = useState([]); + const [filteredPersonalDetails, setFilteredPersonalDetails] = useState([]); + const [filteredUserToInvite, setFilteredUserToInvite] = useState(null); + const [filteredCurrentUserOption, setFilteredCurrentUserOption] = useState(null); + const [isLoading, setIsLoading] = React.useState(true); const allPersonalDetails = usePersonalDetails() || CONST.EMPTY_OBJECT; - const betas = useBetas(); - const [isLoading, setIsLoading] = useState(true); - const [searchValue, debouncedSearchValue, setSearchValue] = useDebouncedState(''); - const options = useMemo(() => { + const {inputCallbackRef} = useAutoFocusInput(); + + const updateOptions = useCallback(() => { const {recentReports, personalDetails, userToInvite, currentUserOption} = OptionsListUtils.getFilteredOptions( - reports, + props.reports, allPersonalDetails, - betas, - debouncedSearchValue.trim(), + props.betas, + searchValue.trim(), [], CONST.EXPENSIFY_EMAILS, false, @@ -76,56 +107,50 @@ function useOptions({reports}) { true, ); - const headerMessage = OptionsListUtils.getHeaderMessage(recentReports?.length + personalDetails?.length !== 0 || currentUserOption, Boolean(userToInvite), debouncedSearchValue); + setHeaderMessage(OptionsListUtils.getHeaderMessage(recentReports?.length + personalDetails?.length !== 0 || currentUserOption, Boolean(userToInvite), searchValue)); + setFilteredUserToInvite(userToInvite); + setFilteredRecentReports(recentReports); + setFilteredPersonalDetails(personalDetails); + setFilteredCurrentUserOption(currentUserOption); if (isLoading) { setIsLoading(false); } + }, [props, searchValue, allPersonalDetails, isLoading]); - return { - userToInvite, - recentReports, - personalDetails, - currentUserOption, - headerMessage, + useEffect(() => { + const debouncedSearch = _.debounce(updateOptions, 200); + debouncedSearch(); + return () => { + debouncedSearch.cancel(); }; - }, [debouncedSearchValue, allPersonalDetails, isLoading, betas, reports]); - - return {...options, isLoading, searchValue, debouncedSearchValue, setSearchValue}; -} - -function TaskAssigneeSelectorModal({reports, task, rootParentReportPolicy}) { - const styles = useThemeStyles(); - const route = useRoute(); - const {translate} = useLocalize(); - const session = useSession(); - const currentUserPersonalDetails = useCurrentUserPersonalDetails(); - const {userToInvite, recentReports, personalDetails, currentUserOption, isLoading, searchValue, setSearchValue, headerMessage} = useOptions({reports, task}); + }, [updateOptions]); const onChangeText = (newSearchTerm = '') => { setSearchValue(newSearchTerm); }; const report = useMemo(() => { - if (!route.params || !route.params.reportID) { + if (!props.route.params || !props.route.params.reportID) { return null; } - if (report && !ReportUtils.isTaskReport(report)) { - Navigation.isNavigationReady().then(() => { - Navigation.dismissModal(report.reportID); - }); - } - return reports[`${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID}`]; - }, [reports, route]); + return props.reports[`${ONYXKEYS.COLLECTION.REPORT}${props.route.params.reportID}`]; + }, [props.reports, props.route.params]); + + if (report && !ReportUtils.isTaskReport(report)) { + Navigation.isNavigationReady().then(() => { + Navigation.dismissModal(report.reportID); + }); + } const sections = useMemo(() => { const sectionsList = []; let indexOffset = 0; - if (currentUserOption) { + if (filteredCurrentUserOption) { sectionsList.push({ - title: translate('newTaskPage.assignMe'), - data: [currentUserOption], + title: props.translate('newTaskPage.assignMe'), + data: [filteredCurrentUserOption], shouldShow: true, indexOffset, }); @@ -133,31 +158,31 @@ function TaskAssigneeSelectorModal({reports, task, rootParentReportPolicy}) { } sectionsList.push({ - title: translate('common.recents'), - data: recentReports, - shouldShow: recentReports?.length > 0, + title: props.translate('common.recents'), + data: filteredRecentReports, + shouldShow: filteredRecentReports?.length > 0, indexOffset, }); - indexOffset += recentReports?.length; + indexOffset += filteredRecentReports?.length; sectionsList.push({ - title: translate('common.contacts'), - data: personalDetails, - shouldShow: personalDetails?.length > 0, + title: props.translate('common.contacts'), + data: filteredPersonalDetails, + shouldShow: filteredPersonalDetails?.length > 0, indexOffset, }); - indexOffset += personalDetails?.length; + indexOffset += filteredPersonalDetails?.length; - if (userToInvite) { + if (filteredUserToInvite) { sectionsList.push({ - data: [userToInvite], + data: [filteredUserToInvite], shouldShow: true, indexOffset, }); } return sectionsList; - }, [currentUserOption, personalDetails, recentReports, userToInvite, translate]); + }, [filteredCurrentUserOption, filteredPersonalDetails, filteredRecentReports, filteredUserToInvite, props]); const selectReport = useCallback( (option) => { @@ -171,22 +196,20 @@ function TaskAssigneeSelectorModal({reports, task, rootParentReportPolicy}) { const assigneeChatReport = Task.setAssigneeValue(option.login, option.accountID, report.reportID, OptionsListUtils.isCurrentUser(option)); // Pass through the selected assignee - Task.editTaskAssignee(report, session.accountID, option.login, option.accountID, assigneeChatReport); + Task.editTaskAssignee(report, props.session.accountID, option.login, option.accountID, assigneeChatReport); } Navigation.dismissModalWithReport(report); // If there's no report, we're creating a new task } else if (option.accountID) { - Task.setAssigneeValue(option.login, option.accountID, task.shareDestination, OptionsListUtils.isCurrentUser(option)); + Task.setAssigneeValue(option.login, option.accountID, props.task.shareDestination, OptionsListUtils.isCurrentUser(option)); Navigation.goBack(ROUTES.NEW_TASK); } }, - [session.accountID, task.shareDestination, report], + [props.session.accountID, props.task.shareDestination, report], ); - const handleBackButtonPress = useCallback(() => (lodashGet(route.params, 'reportID') ? Navigation.dismissModal() : Navigation.goBack(ROUTES.NEW_TASK)), [route.params]); - const isOpen = ReportUtils.isOpenTaskReport(report); - const canModifyTask = Task.canModifyTask(report, currentUserPersonalDetails.accountID, lodashGet(rootParentReportPolicy, 'role', '')); + const canModifyTask = Task.canModifyTask(report, props.currentUserPersonalDetails.accountID, lodashGet(props.rootParentReportPolicy, 'role', '')); const isTaskNonEditable = ReportUtils.isTaskReport(report) && (!canModifyTask || !isOpen); return ( @@ -197,19 +220,21 @@ function TaskAssigneeSelectorModal({reports, task, rootParentReportPolicy}) { {({didScreenTransitionEnd, safeAreaPaddingBottomStyle}) => ( (lodashGet(props.route.params, 'reportID') ? Navigation.dismissModal() : Navigation.goBack(ROUTES.NEW_TASK))} /> - @@ -223,13 +248,21 @@ TaskAssigneeSelectorModal.propTypes = propTypes; TaskAssigneeSelectorModal.defaultProps = defaultProps; export default compose( + withLocalize, + withCurrentUserPersonalDetails, withOnyx({ reports: { key: ONYXKEYS.COLLECTION.REPORT, }, + betas: { + key: ONYXKEYS.BETAS, + }, task: { key: ONYXKEYS.TASK, }, + session: { + key: ONYXKEYS.SESSION, + }, }), withOnyx({ rootParentReportPolicy: { @@ -238,7 +271,7 @@ export default compose( const rootParentReport = ReportUtils.getRootParentReport(report); return `${ONYXKEYS.COLLECTION.POLICY}${rootParentReport ? rootParentReport.policyID : '0'}`; }, - selector: (policy) => lodashPick(policy, ['role']), + selector: (policy) => _.pick(policy, ['role']), }, }), )(TaskAssigneeSelectorModal);