diff --git a/src/components/OptionsList/types.ts b/src/components/OptionsList/types.ts index 12e44adb5800..4c9a0e60a7e3 100644 --- a/src/components/OptionsList/types.ts +++ b/src/components/OptionsList/types.ts @@ -108,13 +108,13 @@ type OptionsListProps = { renderFooterContent?: () => JSX.Element; /** Whether to show a button pill instead of a standard tickbox */ - shouldShowMultipleOptionSelectorAsButton: boolean; + shouldShowMultipleOptionSelectorAsButton?: boolean; /** Text for button pill */ - multipleOptionSelectorButtonText: string; + multipleOptionSelectorButtonText?: string; /** Callback to fire when the multiple selector (tickbox or button) is clicked */ - onAddToSelection: () => void; + onAddToSelection?: () => void; /** Safe area style */ safeAreaPaddingBottomStyle?: StyleProp; diff --git a/src/pages/ReportParticipantsPage.js b/src/pages/ReportParticipantsPage.tsx similarity index 59% rename from src/pages/ReportParticipantsPage.js rename to src/pages/ReportParticipantsPage.tsx index 7dbc1c7036c4..694284a900d0 100755 --- a/src/pages/ReportParticipantsPage.js +++ b/src/pages/ReportParticipantsPage.tsx @@ -1,75 +1,61 @@ -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; import React from 'react'; import {View} from 'react-native'; +import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import OptionsList from '@components/OptionsList'; import ScreenWrapper from '@components/ScreenWrapper'; -import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; +import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import compose from '@libs/compose'; import * as LocalePhoneNumber from '@libs/LocalePhoneNumber'; +import type * as Localize from '@libs/Localize'; import Navigation from '@libs/Navigation/Navigation'; import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import * as ReportUtils from '@libs/ReportUtils'; +import type {OptionData} from '@libs/ReportUtils'; import * as UserUtils from '@libs/UserUtils'; import CONST from '@src/CONST'; +import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import type {PersonalDetailsList, Report} from '@src/types/onyx'; +import type {WithReportOrNotFoundProps} from './home/report/withReportOrNotFound'; import withReportOrNotFound from './home/report/withReportOrNotFound'; -import personalDetailsPropType from './personalDetailsPropType'; -import reportPropTypes from './reportPropTypes'; -const propTypes = { - /* Onyx Props */ - - /** The personal details of the person who is logged in */ - personalDetails: PropTypes.objectOf(personalDetailsPropType), - - /** The active report */ - report: reportPropTypes.isRequired, - - /** Route params */ - route: PropTypes.shape({ - params: PropTypes.shape({ - /** Report ID passed via route r/:reportID/participants */ - reportID: PropTypes.string, - }), - }).isRequired, - - ...withLocalizePropTypes, +type ReportParticipantsPageOnyxProps = { + /** Personal details of all the users */ + personalDetails: OnyxEntry; }; -const defaultProps = { - personalDetails: {}, -}; +type ReportParticipantsPageProps = ReportParticipantsPageOnyxProps & WithReportOrNotFoundProps; /** * Returns all the participants in the active report * - * @param {Object} report The active report object - * @param {Object} personalDetails The personal details of the users - * @param {Object} translate The localize - * @return {Array} + * @param report The active report object + * @param personalDetails The personal details of the users + * @param translate The localize */ -const getAllParticipants = (report, personalDetails, translate) => - _.chain(ReportUtils.getVisibleMemberIDs(report)) +const getAllParticipants = ( + report: OnyxEntry, + personalDetails: OnyxEntry, + translate: (phraseKey: TKey, ...phraseParameters: Localize.PhraseParameters>) => string, +): OptionData[] => + ReportUtils.getVisibleMemberIDs(report) .map((accountID, index) => { - const userPersonalDetail = lodashGet(personalDetails, accountID, {displayName: personalDetails.displayName || translate('common.hidden'), avatar: ''}); - const userLogin = LocalePhoneNumber.formatPhoneNumber(userPersonalDetail.login || '') || translate('common.hidden'); + const userPersonalDetail = personalDetails?.[accountID]; + const userLogin = LocalePhoneNumber.formatPhoneNumber(userPersonalDetail?.login ?? '') ?? translate('common.hidden'); const displayName = PersonalDetailsUtils.getDisplayNameOrDefault(userPersonalDetail); return { alternateText: userLogin, displayName, - accountID: userPersonalDetail.accountID, + accountID: userPersonalDetail?.accountID ?? accountID, icons: [ { id: accountID, - source: UserUtils.getAvatar(userPersonalDetail.avatar, accountID), + source: UserUtils.getAvatar(userPersonalDetail?.avatar ?? '', accountID), name: userLogin, type: CONST.ICON_TYPE_AVATAR, }, @@ -79,16 +65,18 @@ const getAllParticipants = (report, personalDetails, translate) => text: displayName, tooltipText: userLogin, participantsList: [{accountID, displayName}], + reportID: report?.reportID ?? '', }; }) - .sortBy((participant) => participant.displayName.toLowerCase()) - .value(); + .sort((a, b) => a.displayName.localeCompare(b.displayName.toLowerCase())); -function ReportParticipantsPage(props) { +function ReportParticipantsPage({report, personalDetails}: ReportParticipantsPageProps) { + const {translate} = useLocalize(); const styles = useThemeStyles(); - const participants = _.map(getAllParticipants(props.report, props.personalDetails, props.translate), (participant) => ({ + + const participants = getAllParticipants(report, personalDetails, translate).map((participant) => ({ ...participant, - isDisabled: ReportUtils.isOptimisticPersonalDetail(participant.accountID), + isDisabled: participant?.accountID ? ReportUtils.isOptimisticPersonalDetail(participant.accountID) : false, })); return ( @@ -97,20 +85,20 @@ function ReportParticipantsPage(props) { testID={ReportParticipantsPage.displayName} > {({safeAreaPaddingBottomStyle}) => ( - + - {Boolean(participants.length) && ( + {participants?.length && ( { + onSelectRow={(option: OptionData) => { + if (!option.accountID) { + return; + } Navigation.navigate(ROUTES.PROFILE.getRoute(option.accountID)); }} hideSectionHeaders @@ -139,16 +130,12 @@ function ReportParticipantsPage(props) { ); } -ReportParticipantsPage.propTypes = propTypes; -ReportParticipantsPage.defaultProps = defaultProps; ReportParticipantsPage.displayName = 'ReportParticipantsPage'; -export default compose( - withLocalize, - withReportOrNotFound(), - withOnyx({ +export default withReportOrNotFound()( + withOnyx({ personalDetails: { key: ONYXKEYS.PERSONAL_DETAILS_LIST, }, - }), -)(ReportParticipantsPage); + })(ReportParticipantsPage), +); diff --git a/src/pages/home/report/withReportOrNotFound.tsx b/src/pages/home/report/withReportOrNotFound.tsx index 5c10cc6fc7ad..7214e6b6f3ea 100644 --- a/src/pages/home/report/withReportOrNotFound.tsx +++ b/src/pages/home/report/withReportOrNotFound.tsx @@ -13,7 +13,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type * as OnyxTypes from '@src/types/onyx'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; -type OnyxProps = { +type WithReportOrNotFoundOnyxProps = { /** The report currently being looked at */ report: OnyxEntry; /** The policies which the user has access to */ @@ -24,7 +24,7 @@ type OnyxProps = { isLoadingReportData: OnyxEntry; }; -type WithReportOrNotFoundProps = OnyxProps & { +type WithReportOrNotFoundProps = WithReportOrNotFoundOnyxProps & { route: RouteProp<{params: {reportID: string}}>; }; @@ -32,7 +32,7 @@ export default function ( shouldRequireReportID = true, ): ( WrappedComponent: React.ComponentType>, -) => React.ComponentType, keyof OnyxProps>> { +) => React.ComponentType, keyof WithReportOrNotFoundOnyxProps>> { return function (WrappedComponent: ComponentType>) { function WithReportOrNotFound(props: TProps, ref: ForwardedRef) { const contentShown = React.useRef(false); @@ -87,7 +87,7 @@ export default function ( WithReportOrNotFound.displayName = `withReportOrNotFound(${getComponentDisplayName(WrappedComponent)})`; - return withOnyx, OnyxProps>({ + return withOnyx, WithReportOrNotFoundOnyxProps>({ report: { key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID}`, }, @@ -103,4 +103,5 @@ export default function ( })(React.forwardRef(WithReportOrNotFound)); }; } + export type {WithReportOrNotFoundProps}; diff --git a/src/types/onyx/PersonalDetails.ts b/src/types/onyx/PersonalDetails.ts index baf3b9d3801a..8d02d7cf26fc 100644 --- a/src/types/onyx/PersonalDetails.ts +++ b/src/types/onyx/PersonalDetails.ts @@ -43,7 +43,7 @@ type PersonalDetails = { phoneNumber?: string; /** Avatar URL of the current user from their personal details */ - avatar: AvatarSource; + avatar?: AvatarSource; /** Avatar thumbnail URL of the current user from their personal details */ avatarThumbnail?: string;