From 49269d0a5cfeaed8df487e716fff6b789c9e083d Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Mon, 9 Dec 2024 16:06:11 +0100 Subject: [PATCH 01/22] remove the Just track it button --- .../MoneyRequestParticipantsSelector.tsx | 35 +------------------ .../step/IOURequestStepParticipants.tsx | 19 ---------- 2 files changed, 1 insertion(+), 53 deletions(-) diff --git a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx index bf5101848cd9..855950bbe03f 100644 --- a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx +++ b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx @@ -7,8 +7,6 @@ import {useOnyx} from 'react-native-onyx'; import Button from '@components/Button'; import EmptySelectionListContent from '@components/EmptySelectionListContent'; import FormHelpMessage from '@components/FormHelpMessage'; -import * as Expensicons from '@components/Icon/Expensicons'; -import MenuItem from '@components/MenuItem'; import {usePersonalDetails} from '@components/OnyxProvider'; import {useOptionsList} from '@components/OptionListContextProvider'; import ReferralProgramCTA from '@components/ReferralProgramCTA'; @@ -42,9 +40,6 @@ type MoneyRequestParticipantsSelectorProps = { /** Callback to add participants in MoneyRequestModal */ onParticipantsAdded: (value: Participant[]) => void; - /** Callback to navigate to Track Expense confirmation flow */ - onTrackExpensePress?: () => void; - /** Selected participants from MoneyRequestModal with login */ participants?: Participant[] | typeof CONST.EMPTY_ARRAY; @@ -53,20 +48,9 @@ type MoneyRequestParticipantsSelectorProps = { /** The action of the IOU, i.e. create, split, move */ action: IOUAction; - - /** Whether we should display the Track Expense button at the top of the participants list */ - shouldDisplayTrackExpenseButton?: boolean; }; -function MoneyRequestParticipantsSelector({ - participants = CONST.EMPTY_ARRAY, - onTrackExpensePress, - onFinish, - onParticipantsAdded, - iouType, - action, - shouldDisplayTrackExpenseButton, -}: MoneyRequestParticipantsSelectorProps) { +function MoneyRequestParticipantsSelector({participants = CONST.EMPTY_ARRAY, onFinish, onParticipantsAdded, iouType, action}: MoneyRequestParticipantsSelectorProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState(''); @@ -347,22 +331,6 @@ function MoneyRequestParticipantsSelector({ const shouldShowReferralBanner = !isDismissed && iouType !== CONST.IOU.TYPE.INVOICE && !shouldShowListEmptyContent; - const headerContent = useMemo(() => { - if (!shouldDisplayTrackExpenseButton) { - return; - } - - // We only display the track expense button if the user is coming from the combined submit/track flow. - return ( - - ); - }, [shouldDisplayTrackExpenseButton, translate, onTrackExpensePress]); - const footerContent = useMemo(() => { if (isDismissed && !shouldShowSplitBillErrorMessage && !participants.length) { return; @@ -448,7 +416,6 @@ function MoneyRequestParticipantsSelector({ shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} onSelectRow={onSelectRow} shouldSingleExecuteRowSelect - headerContent={headerContent} footerContent={footerContent} listEmptyContent={} headerMessage={header} diff --git a/src/pages/iou/request/step/IOURequestStepParticipants.tsx b/src/pages/iou/request/step/IOURequestStepParticipants.tsx index fb2484ea414f..c505a88f42c6 100644 --- a/src/pages/iou/request/step/IOURequestStepParticipants.tsx +++ b/src/pages/iou/request/step/IOURequestStepParticipants.tsx @@ -63,9 +63,6 @@ function IOURequestStepParticipants({ return translate('iou.chooseRecipient'); }, [iouType, translate, isSplitRequest, action]); - const selfDMReportID = useMemo(() => ReportUtils.findSelfDMReportID(), []); - const shouldDisplayTrackExpenseButton = !!selfDMReportID && iouType === CONST.IOU.TYPE.CREATE; - const receiptFilename = transaction?.filename; const receiptPath = transaction?.receipt?.source; const receiptType = transaction?.receipt?.type; @@ -142,20 +139,6 @@ function IOURequestStepParticipants({ IOUUtils.navigateToStartMoneyRequestStep(iouRequestType, iouType, transactionID, reportID, action); }, [iouRequestType, iouType, transactionID, reportID, action]); - const trackExpense = () => { - // If coming from the combined submit/track flow and the user proceeds to just track the expense, - // we will use the track IOU type in the confirmation flow. - if (!selfDMReportID) { - return; - } - - const rateID = DistanceRequestUtils.getCustomUnitRateID(selfDMReportID); - IOU.setCustomUnitRateID(transactionID, rateID); - IOU.setMoneyRequestParticipantsFromReport(transactionID, ReportUtils.getReport(selfDMReportID)); - const iouConfirmationPageRoute = ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(action, CONST.IOU.TYPE.TRACK, transactionID, selfDMReportID); - Navigation.navigate(iouConfirmationPageRoute); - }; - useEffect(() => { const isCategorizing = action === CONST.IOU.ACTION.CATEGORIZE; const isShareAction = action === CONST.IOU.ACTION.SHARE; @@ -184,10 +167,8 @@ function IOURequestStepParticipants({ participants={isSplitRequest ? participants : []} onParticipantsAdded={addParticipant} onFinish={goToNextStep} - onTrackExpensePress={trackExpense} iouType={iouType} action={action} - shouldDisplayTrackExpenseButton={shouldDisplayTrackExpenseButton} /> ); From 7a2556d3d59712801f03f1eee44c116778569140 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Mon, 9 Dec 2024 16:15:04 +0100 Subject: [PATCH 02/22] add the create $amount expense label --- src/components/MoneyRequestConfirmationList.tsx | 4 ++-- src/languages/en.ts | 1 + src/languages/es.ts | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index 6a888a09b60b..f632465703ca 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -410,7 +410,7 @@ function MoneyRequestConfirmationList({ text = translate('common.next'); } } else if (isTypeTrackExpense) { - text = translate('iou.trackExpense'); + text = translate('iou.createExpenseWithAmount', {amount: formattedAmount}); } else if (isTypeSplit && iouAmount === 0) { text = translate('iou.splitExpense'); } else if ((receiptPath && isTypeRequest) || isDistanceRequestWithPendingRoute) { @@ -419,7 +419,7 @@ function MoneyRequestConfirmationList({ text = translate('iou.submitAmount', {amount: formattedAmount}); } } else { - const translationKey = isTypeSplit ? 'iou.splitAmount' : 'iou.submitAmount'; + const translationKey = isTypeSplit ? 'iou.splitAmount' : 'iou.createExpenseWithAmount'; text = translate(translationKey, {amount: formattedAmount}); } return [ diff --git a/src/languages/en.ts b/src/languages/en.ts index d79695ed8b48..5854906729a5 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -859,6 +859,7 @@ const translations = { createExpense: 'Create expense', trackExpense: 'Track expense', chooseRecipient: 'Choose recipient', + createExpenseWithAmount: ({amount}: {amount: string}) => `Create ${amount} expense`, confirmDetails: 'Confirm details', pay: 'Pay', cancelPayment: 'Cancel payment', diff --git a/src/languages/es.ts b/src/languages/es.ts index 5ce47db18d35..f97975ec3707 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -855,6 +855,7 @@ const translations = { trackExpense: 'Seguimiento de gastos', chooseRecipient: 'Elige destinatario', confirmDetails: 'Confirma los detalles', + createExpenseWithAmount: ({amount}: {amount: string}) => `Crea un gasto de ${amount}`, pay: 'Pagar', cancelPayment: 'Cancelar el pago', cancelPaymentConfirmation: '¿Estás seguro de que quieres cancelar este pago?', From 103bf6cba97b85a4c30a78c07dc38c137cb9f4e0 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Tue, 10 Dec 2024 16:28:14 +0100 Subject: [PATCH 03/22] add Workspace and Personal sections to recipients list --- src/libs/OptionsListUtils.ts | 58 ++++++++++++++++++- .../MoneyRequestParticipantsSelector.tsx | 25 +++++++- .../step/IOURequestStepParticipants.tsx | 25 +++++++- 3 files changed, 103 insertions(+), 5 deletions(-) diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index 2470a02fb62a..452e6fc361c6 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -113,6 +113,8 @@ type GetOptionsConfig = { shouldAcceptName?: boolean; recentAttendees?: Attendee[]; shouldBoldTitleByDefault?: boolean; + shouldSeparateWorkspaceChat?: boolean; + shouldSeparateSelfDMChat?: boolean; }; type GetUserToInviteConfig = { @@ -146,6 +148,8 @@ type Options = { personalDetails: ReportUtils.OptionData[]; userToInvite: ReportUtils.OptionData | null; currentUserOption: ReportUtils.OptionData | null | undefined; + recentWorkspaceChats?: ReportUtils.OptionData[]; + selfDMChat?: ReportUtils.OptionData | undefined; }; type PreviewConfig = {showChatPreviewLine?: boolean; forcePolicyNamePreview?: boolean; showPersonalDetails?: boolean}; @@ -1070,6 +1074,8 @@ function getOptions( action, recentAttendees, shouldBoldTitleByDefault = true, + shouldSeparateSelfDMChat = false, + shouldSeparateWorkspaceChat = false, }: GetOptionsConfig = {}, ): Options { const topmostReportId = Navigation.getTopmostReportId() ?? '-1'; @@ -1280,6 +1286,17 @@ function getOptions( } const currentUserOption = allPersonalDetailsOptions.find((personalDetailsOption) => personalDetailsOption.login === currentUserLogin); + let recentWorkspaceChats: ReportUtils.OptionData[] = []; + let selfDMChat: ReportUtils.OptionData | undefined; + + if (shouldSeparateWorkspaceChat) { + recentWorkspaceChats = recentReportOptions.filter((option) => option.isPolicyExpenseChat); + recentReportOptions = recentReportOptions.filter((option) => !option.isPolicyExpenseChat); + } + if (shouldSeparateSelfDMChat) { + selfDMChat = recentReportOptions.find((option) => option.isSelfDM); + recentReportOptions = recentReportOptions.filter((option) => !option.isSelfDM); + } return { personalDetails: personalDetailsOptions, @@ -1288,6 +1305,8 @@ function getOptions( // User to invite is generated by the search input of a user. // As this function isn't concerned with any search input yet, this is null (will be set when using filterOptions). userToInvite: null, + recentWorkspaceChats, + selfDMChat, }; } @@ -1520,6 +1539,7 @@ function formatSectionsFromSearchTerm( filteredPersonalDetails: ReportUtils.OptionData[], personalDetails: OnyxEntry = {}, shouldGetOptionDetails = false, + filteredRecentWorkspaceChats: ReportUtils.OptionData[] = [], ): SectionForSearchTerm { // We show the selected participants at the top of the list when there is no search term or maximum number of participants has already been selected // However, if there is a search term we remove the selected participants from the top of the list unless they are part of the search results @@ -1545,8 +1565,10 @@ function formatSectionsFromSearchTerm( const selectedParticipantsWithoutDetails = selectedOptions.filter((participant) => { const accountID = participant.accountID ?? null; const isPartOfSearchTerm = getPersonalDetailSearchTerms(participant).join(' ').toLowerCase().includes(cleanSearchTerm); - const isReportInRecentReports = filteredRecentReports.some((report) => report.accountID === accountID); + const isReportInRecentReports = + filteredRecentReports.some((report) => report.accountID === accountID) || filteredRecentWorkspaceChats.some((report) => report.accountID === accountID); const isReportInPersonalDetails = filteredPersonalDetails.some((personalDetail) => personalDetail.accountID === accountID); + return isPartOfSearchTerm && !isReportInRecentReports && !isReportInPersonalDetails; }); @@ -1610,10 +1632,13 @@ function filterOptions(options: Options, searchInputValue: string, config?: Filt if (searchInputValue.trim() === '' && maxRecentReportsToShow > 0) { const recentReports = options.recentReports.slice(0, maxRecentReportsToShow); const personalDetails = filteredPersonalDetailsOfRecentReports(recentReports, options.personalDetails); + const recentWorkspaceChats = options.recentWorkspaceChats?.slice(0, maxRecentReportsToShow); + return { ...options, recentReports, personalDetails, + recentWorkspaceChats, }; } @@ -1651,6 +1676,28 @@ function filterOptions(options: Options, searchInputValue: string, config?: Filt return uniqFast(values); }); + + const recentWorkspaceChats = filterArrayByMatch(items.recentWorkspaceChats ?? [], term, (item) => { + const values: string[] = []; + if (item.text) { + values.push(item.text); + } + if (item.login) { + values.push(item.login); + values.push(item.login.replace(CONST.EMAIL_SEARCH_REGEX, '')); + } + if (item.isThread) { + if (item.alternateText) { + values.push(item.alternateText); + } + } else if (!!item.isChatRoom || !!item.isPolicyExpenseChat) { + if (item.subtitle) { + values.push(item.subtitle); + } + } + return uniqFast(values); + }); + const personalDetails = filterArrayByMatch(items.personalDetails, term, (item) => uniqFast(getPersonalDetailSearchTerms(item))); const currentUserOptionSearchText = items.currentUserOption ? uniqFast(getCurrentUserSearchTerms(items.currentUserOption)).join(' ') : ''; @@ -1661,10 +1708,11 @@ function filterOptions(options: Options, searchInputValue: string, config?: Filt personalDetails: personalDetails ?? [], userToInvite: null, currentUserOption, + recentWorkspaceChats: recentWorkspaceChats ?? [], }; }, options); - const {recentReports, personalDetails} = matchResults; + const {recentReports, personalDetails, recentWorkspaceChats = []} = matchResults; const personalDetailsWithoutDMs = filteredPersonalDetailsOfRecentReports(recentReports, personalDetails); @@ -1696,12 +1744,18 @@ function filterOptions(options: Options, searchInputValue: string, config?: Filt recentReports.splice(maxRecentReportsToShow); } + if (maxRecentReportsToShow > 0 && recentWorkspaceChats.length > maxRecentReportsToShow) { + recentWorkspaceChats.splice(maxRecentReportsToShow); + } + const sortedRecentReports = orderOptions(filteredRecentReports, searchValue, {preferChatroomsOverThreads, preferPolicyExpenseChat, preferRecentExpenseReports}); return { personalDetails: filteredPersonalDetails, recentReports: sortedRecentReports, userToInvite, currentUserOption: matchResults.currentUserOption, + recentWorkspaceChats, + selfDMChat: options.selfDMChat, }; } diff --git a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx index 855950bbe03f..f1037848e2e5 100644 --- a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx +++ b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx @@ -108,6 +108,9 @@ function MoneyRequestParticipantsSelector({participants = CONST.EMPTY_ARRAY, onF includeInvoiceRooms: iouType === CONST.IOU.TYPE.INVOICE, action, maxRecentReportsToShow: 0, + shouldSeparateSelfDMChat: true, + shouldSeparateWorkspaceChat: true, + includeSelfDM: true, }, ); @@ -130,6 +133,8 @@ function MoneyRequestParticipantsSelector({participants = CONST.EMPTY_ARRAY, onF personalDetails: [], currentUserOption: null, headerMessage: '', + recentWorkspaceChats: [], + selfDMChat: null, }; } @@ -165,6 +170,17 @@ function MoneyRequestParticipantsSelector({participants = CONST.EMPTY_ARRAY, onF newSections.push(formatResults.section); + newSections.push({ + title: translate('workspace.common.workspace'), + data: chatOptions.recentWorkspaceChats ?? [], + shouldShow: (chatOptions.recentWorkspaceChats ?? []).length > 0, + }); + newSections.push({ + title: translate('workspace.invoices.paymentMethods.personal'), + data: chatOptions.selfDMChat ? [chatOptions.selfDMChat] : [], + shouldShow: !!chatOptions.selfDMChat, + }); + newSections.push({ title: translate('common.recents'), data: chatOptions.recentReports, @@ -206,6 +222,8 @@ function MoneyRequestParticipantsSelector({participants = CONST.EMPTY_ARRAY, onF participants, chatOptions.recentReports, chatOptions.personalDetails, + chatOptions.selfDMChat, + chatOptions.recentWorkspaceChats, chatOptions.userToInvite, personalDetails, translate, @@ -221,7 +239,7 @@ function MoneyRequestParticipantsSelector({participants = CONST.EMPTY_ARRAY, onF (option: Participant) => { const newParticipants: Participant[] = [ { - ...lodashPick(option, 'accountID', 'login', 'isPolicyExpenseChat', 'reportID', 'searchText', 'policyID'), + ...lodashPick(option, 'accountID', 'login', 'isPolicyExpenseChat', 'reportID', 'searchText', 'policyID', 'isSelfDM'), selected: true, iouType, }, @@ -238,7 +256,10 @@ function MoneyRequestParticipantsSelector({participants = CONST.EMPTY_ARRAY, onF } onParticipantsAdded(newParticipants); - onFinish(); + + if (!option.isSelfDM) { + onFinish(); + } }, // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps -- we don't want to trigger this callback when iouType changes [onFinish, onParticipantsAdded, currentUserLogin], diff --git a/src/pages/iou/request/step/IOURequestStepParticipants.tsx b/src/pages/iou/request/step/IOURequestStepParticipants.tsx index c505a88f42c6..95e0e3ffd693 100644 --- a/src/pages/iou/request/step/IOURequestStepParticipants.tsx +++ b/src/pages/iou/request/step/IOURequestStepParticipants.tsx @@ -63,6 +63,8 @@ function IOURequestStepParticipants({ return translate('iou.chooseRecipient'); }, [iouType, translate, isSplitRequest, action]); + const selfDMReportID = useMemo(() => ReportUtils.findSelfDMReportID(), []); + const receiptFilename = transaction?.filename; const receiptPath = transaction?.receipt?.source; const receiptType = transaction?.receipt?.type; @@ -78,10 +80,31 @@ function IOURequestStepParticipants({ IOU.navigateToStartStepIfScanFileCannotBeRead(receiptFilename ?? '', receiptPath ?? '', () => {}, iouRequestType, iouType, transactionID, reportID, receiptType ?? ''); }, [receiptType, receiptPath, receiptFilename, iouRequestType, iouType, transactionID, reportID, action]); + const trackExpense = useCallback(() => { + // If coming from the combined submit/track flow and the user proceeds to just track the expense, + // we will use the track IOU type in the confirmation flow. + if (!selfDMReportID) { + return; + } + + const rateID = DistanceRequestUtils.getCustomUnitRateID(selfDMReportID); + IOU.setCustomUnitRateID(transactionID, rateID); + IOU.setMoneyRequestParticipantsFromReport(transactionID, ReportUtils.getReport(selfDMReportID)); + const iouConfirmationPageRoute = ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(action, CONST.IOU.TYPE.TRACK, transactionID, selfDMReportID); + Navigation.navigate(iouConfirmationPageRoute); + }, [action, selfDMReportID, transactionID]); + const addParticipant = useCallback( (val: Participant[]) => { HttpUtils.cancelPendingRequests(READ_COMMANDS.SEARCH_FOR_REPORTS); + const firstParticipant = val.at(0); + + if (firstParticipant?.isSelfDM) { + trackExpense(); + return; + } + const firstParticipantReportID = val.at(0)?.reportID ?? ''; const rateID = DistanceRequestUtils.getCustomUnitRateID(firstParticipantReportID); const isInvoice = iouType === CONST.IOU.TYPE.INVOICE && ReportUtils.isInvoiceRoomWithID(firstParticipantReportID); @@ -100,7 +123,7 @@ function IOURequestStepParticipants({ // When a participant is selected, the reportID needs to be saved because that's the reportID that will be used in the confirmation step. selectedReportID.current = firstParticipantReportID || reportID; }, - [iouType, reportID, transactionID], + [iouType, reportID, trackExpense, transactionID], ); const goToNextStep = useCallback(() => { From 052b1ffb5d0d699d2d5ea2697265300630ed2855 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Wed, 11 Dec 2024 15:20:20 +0100 Subject: [PATCH 04/22] update translation, add return type --- src/languages/es.ts | 2 +- src/libs/OptionsListUtils.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/languages/es.ts b/src/languages/es.ts index d6e378fea383..75897713fbad 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -857,7 +857,7 @@ const translations = { trackExpense: 'Seguimiento de gastos', chooseRecipient: 'Elige destinatario', confirmDetails: 'Confirma los detalles', - createExpenseWithAmount: ({amount}: {amount: string}) => `Crea un gasto de ${amount}`, + createExpenseWithAmount: ({amount}: {amount: string}) => `Crear un gasto de ${amount}`, pay: 'Pagar', cancelPayment: 'Cancelar el pago', cancelPaymentConfirmation: '¿Estás seguro de que quieres cancelar este pago?', diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index 5d9b341a857a..51d65bde11a4 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -1676,7 +1676,7 @@ function filterReports(reports: ReportUtils.OptionData[], searchTerms: string[]) return filteredReports; } -function filterRecentWorkspaceChats(reports: ReportUtils.OptionData[], searchTerms: string[]) { +function filterRecentWorkspaceChats(reports: ReportUtils.OptionData[], searchTerms: string[]): ReportUtils.OptionData[] { const filteredReports = searchTerms.reduceRight( (items, term) => filterArrayByMatch(items, term, (item) => { From 676a76dd001ddc2b990189623753d7e1050c29f4 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Fri, 13 Dec 2024 14:07:06 +0100 Subject: [PATCH 05/22] put default workspace on top of the list --- src/libs/OptionsListUtils.ts | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index 51d65bde11a4..f357d05747a8 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -987,6 +987,23 @@ function orderReportOptionsWithSearch( ); } +function orderWorkspaceOptions(options: ReportUtils.OptionData[]): ReportUtils.OptionData[] { + return lodashOrderBy( + options, + [ + (option) => { + // Put default workspace on top + if (option.isPolicyExpenseChat && option.policyID === activePolicyID) { + return 0; + } + + return 1; + }, + ], + ['asc'], + ); +} + function sortComparatorReportOptionByArchivedStatus(option: ReportUtils.OptionData) { return option.private_isArchived ? 1 : 0; } @@ -997,7 +1014,7 @@ function sortComparatorReportOptionByDate(options: ReportUtils.OptionData) { return options.lastVisibleActionCreated ?? ''; } -type ReportAndPersonalDetailOptions = Pick; +type ReportAndPersonalDetailOptions = Pick; function orderOptions(options: ReportAndPersonalDetailOptions): ReportAndPersonalDetailOptions; function orderOptions(options: ReportAndPersonalDetailOptions, searchValue: string, config?: OrderOptionsConfig): ReportAndPersonalDetailOptions; @@ -1009,10 +1026,12 @@ function orderOptions(options: ReportAndPersonalDetailOptions, searchValue?: str orderedReportOptions = orderReportOptions(options.recentReports); } const orderedPersonalDetailsOptions = orderPersonalDetailsOptions(options.personalDetails); + const orderedRecentWorkspaceChats = orderWorkspaceOptions(options?.recentWorkspaceChats ?? []); return { recentReports: orderedReportOptions, personalDetails: orderedPersonalDetailsOptions, + recentWorkspaceChats: orderedRecentWorkspaceChats, }; } From c4fb54a478c183558e74fbeee9eb84fdd3d7e721 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Tue, 17 Dec 2024 12:45:15 +0100 Subject: [PATCH 06/22] replace id fallbacks with CONST.DEFAULT_NUMBER_ID --- .../MoneyRequestConfirmationList.tsx | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index 939f66d2b466..e1516a5918e7 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -177,14 +177,14 @@ function MoneyRequestConfirmationList({ shouldPlaySound = true, isConfirmed, }: MoneyRequestConfirmationListProps) { - const [policyCategoriesReal] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID ?? '-1'}`); - const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID ?? '-1'}`); - const [policyReal] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID ?? '-1'}`); - const [policyDraft] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_DRAFTS}${policyID ?? '-1'}`); - const [defaultMileageRate] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_DRAFTS}${policyID ?? '-1'}`, { + const [policyCategoriesReal] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID ?? CONST.DEFAULT_NUMBER_ID}`); + const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID ?? CONST.DEFAULT_NUMBER_ID}`); + const [policyReal] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID ?? CONST.DEFAULT_NUMBER_ID}`); + const [policyDraft] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_DRAFTS}${policyID ?? CONST.DEFAULT_NUMBER_ID}`); + const [defaultMileageRate] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_DRAFTS}${policyID ?? CONST.DEFAULT_NUMBER_ID}`, { selector: (selectedPolicy) => DistanceRequestUtils.getDefaultMileageRate(selectedPolicy), }); - const [policyCategoriesDraft] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES_DRAFT}${policyID ?? '-1'}`); + const [policyCategoriesDraft] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES_DRAFT}${policyID ?? CONST.DEFAULT_NUMBER_ID}`); const [lastSelectedDistanceRates] = useOnyx(ONYXKEYS.NVP_LAST_SELECTED_DISTANCE_RATES); const [currencyList] = useOnyx(ONYXKEYS.CURRENCY_LIST); @@ -202,11 +202,11 @@ function MoneyRequestConfirmationList({ const isTypeInvoice = iouType === CONST.IOU.TYPE.INVOICE; const isScanRequest = useMemo(() => TransactionUtils.isScanRequest(transaction), [transaction]); - const transactionID = transaction?.transactionID ?? '-1'; - const customUnitRateID = TransactionUtils.getRateID(transaction) ?? '-1'; + const transactionID = transaction?.transactionID ?? CONST.DEFAULT_NUMBER_ID.toString(); + const customUnitRateID = TransactionUtils.getRateID(transaction) ?? CONST.DEFAULT_NUMBER_ID.toString(); useEffect(() => { - if ((customUnitRateID && customUnitRateID !== '-1') || !isDistanceRequest) { + if ((customUnitRateID && customUnitRateID !== '0') || !isDistanceRequest) { return; } @@ -296,7 +296,12 @@ function MoneyRequestConfirmationList({ return true; } - if (!participant.isInvoiceRoom && !participant.isPolicyExpenseChat && !participant.isSelfDM && ReportUtils.isOptimisticPersonalDetail(participant.accountID ?? -1)) { + if ( + !participant.isInvoiceRoom && + !participant.isPolicyExpenseChat && + !participant.isSelfDM && + ReportUtils.isOptimisticPersonalDetail(participant.accountID ?? CONST.DEFAULT_NUMBER_ID) + ) { return true; } @@ -342,7 +347,7 @@ function MoneyRequestConfirmationList({ IOU.setMoneyRequestAmount(transactionID, amount, currency ?? ''); // If it's a split request among individuals, set the split shares - const participantAccountIDs: number[] = selectedParticipantsProp.map((participant) => participant.accountID ?? -1); + const participantAccountIDs: number[] = selectedParticipantsProp.map((participant) => participant.accountID ?? -CONST.DEFAULT_NUMBER_ID); if (isTypeSplit && !isPolicyExpenseChat && amount && transaction?.currency) { IOU.setSplitShares(transaction, amount, currency, participantAccountIDs); } @@ -522,7 +527,7 @@ function MoneyRequestConfirmationList({ rightElement: ( onSplitShareChange(participantOption.accountID ?? -1, Number(value))} + onAmountChange={(value: string) => onSplitShareChange(participantOption.accountID ?? CONST.DEFAULT_NUMBER_ID, Number(value))} maxLength={formattedTotalAmount.length} contentWidth={formattedTotalAmount.length * 8} /> From 50ebfa50df6567b8a87e5b5f852c7e2664259a2e Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Tue, 17 Dec 2024 14:33:54 +0100 Subject: [PATCH 07/22] rename recentWorkspaceChats to workspaceChats --- src/libs/OptionsListUtils.ts | 33 +++++++++---------- .../MoneyRequestParticipantsSelector.tsx | 8 ++--- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index e1da89225967..d06f8e439906 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -141,7 +141,7 @@ type Options = { personalDetails: ReportUtils.OptionData[]; userToInvite: ReportUtils.OptionData | null; currentUserOption: ReportUtils.OptionData | null | undefined; - recentWorkspaceChats?: ReportUtils.OptionData[]; + workspaceChats?: ReportUtils.OptionData[]; selfDMChat?: ReportUtils.OptionData | undefined; }; @@ -1014,7 +1014,7 @@ function sortComparatorReportOptionByDate(options: ReportUtils.OptionData) { return options.lastVisibleActionCreated ?? ''; } -type ReportAndPersonalDetailOptions = Pick; +type ReportAndPersonalDetailOptions = Pick; function orderOptions(options: ReportAndPersonalDetailOptions): ReportAndPersonalDetailOptions; function orderOptions(options: ReportAndPersonalDetailOptions, searchValue: string, config?: OrderOptionsConfig): ReportAndPersonalDetailOptions; @@ -1026,12 +1026,12 @@ function orderOptions(options: ReportAndPersonalDetailOptions, searchValue?: str orderedReportOptions = orderReportOptions(options.recentReports); } const orderedPersonalDetailsOptions = orderPersonalDetailsOptions(options.personalDetails); - const orderedRecentWorkspaceChats = orderWorkspaceOptions(options?.recentWorkspaceChats ?? []); + const orderedWorkspaceChats = orderWorkspaceOptions(options?.workspaceChats ?? []); return { recentReports: orderedReportOptions, personalDetails: orderedPersonalDetailsOptions, - recentWorkspaceChats: orderedRecentWorkspaceChats, + workspaceChats: orderedWorkspaceChats, }; } @@ -1319,11 +1319,11 @@ function getValidOptions( } const currentUserOption = allPersonalDetailsOptions.find((personalDetailsOption) => personalDetailsOption.login === currentUserLogin); - let recentWorkspaceChats: ReportUtils.OptionData[] = []; + let workspaceChats: ReportUtils.OptionData[] = []; let selfDMChat: ReportUtils.OptionData | undefined; if (shouldSeparateWorkspaceChat) { - recentWorkspaceChats = recentReportOptions.filter((option) => option.isPolicyExpenseChat); + workspaceChats = recentReportOptions.filter((option) => option.isPolicyExpenseChat); recentReportOptions = recentReportOptions.filter((option) => !option.isPolicyExpenseChat); } if (shouldSeparateSelfDMChat) { @@ -1338,7 +1338,7 @@ function getValidOptions( // User to invite is generated by the search input of a user. // As this function isn't concerned with any search input yet, this is null (will be set when using filterOptions). userToInvite: null, - recentWorkspaceChats, + workspaceChats, selfDMChat, }; } @@ -1580,7 +1580,7 @@ function formatSectionsFromSearchTerm( filteredPersonalDetails: ReportUtils.OptionData[], personalDetails: OnyxEntry = {}, shouldGetOptionDetails = false, - filteredRecentWorkspaceChats: ReportUtils.OptionData[] = [], + filteredWorkspaceChats: ReportUtils.OptionData[] = [], ): SectionForSearchTerm { // We show the selected participants at the top of the list when there is no search term or maximum number of participants has already been selected // However, if there is a search term we remove the selected participants from the top of the list unless they are part of the search results @@ -1606,8 +1606,7 @@ function formatSectionsFromSearchTerm( const selectedParticipantsWithoutDetails = selectedOptions.filter((participant) => { const accountID = participant.accountID ?? null; const isPartOfSearchTerm = getPersonalDetailSearchTerms(participant).join(' ').toLowerCase().includes(cleanSearchTerm); - const isReportInRecentReports = - filteredRecentReports.some((report) => report.accountID === accountID) || filteredRecentWorkspaceChats.some((report) => report.accountID === accountID); + const isReportInRecentReports = filteredRecentReports.some((report) => report.accountID === accountID) || filteredWorkspaceChats.some((report) => report.accountID === accountID); const isReportInPersonalDetails = filteredPersonalDetails.some((personalDetail) => personalDetail.accountID === accountID); return isPartOfSearchTerm && !isReportInRecentReports && !isReportInPersonalDetails; @@ -1695,7 +1694,7 @@ function filterReports(reports: ReportUtils.OptionData[], searchTerms: string[]) return filteredReports; } -function filterRecentWorkspaceChats(reports: ReportUtils.OptionData[], searchTerms: string[]): ReportUtils.OptionData[] { +function filterWorkspaceChats(reports: ReportUtils.OptionData[], searchTerms: string[]): ReportUtils.OptionData[] { const filteredReports = searchTerms.reduceRight( (items, term) => filterArrayByMatch(items, term, (item) => { @@ -1792,14 +1791,14 @@ function filterOptions(options: Options, searchInputValue: string, config?: Filt searchValue, config, ); - const recentWorkspaceChats = filterRecentWorkspaceChats(options.recentWorkspaceChats ?? [], searchTerms); + const workspaceChats = filterWorkspaceChats(options.workspaceChats ?? [], searchTerms); return { personalDetails, recentReports, userToInvite, currentUserOption, - recentWorkspaceChats, + workspaceChats, }; } @@ -1817,15 +1816,15 @@ function filterAndOrderOptions(options: Options, searchInputValue: string, confi filterResult = filterOptions(options, searchInputValue, config); } - let {recentReports: filteredReports, personalDetails: filteredPersonalDetails, recentWorkspaceChats: filteredRecentWorkspaceChats} = filterResult; + let {recentReports: filteredReports, personalDetails: filteredPersonalDetails, workspaceChats: filteredWorkspaceChats} = filterResult; if (typeof config?.maxRecentReportsToShow === 'number') { filteredReports = orderReportOptionsWithSearch(filteredReports, searchInputValue, config); filteredReports = filteredReports.slice(0, config.maxRecentReportsToShow); } - if (typeof config?.maxRecentReportsToShow === 'number' && filteredRecentWorkspaceChats && filteredRecentWorkspaceChats?.length > config.maxRecentReportsToShow) { - filteredRecentWorkspaceChats = filteredRecentWorkspaceChats.slice(0, config.maxRecentReportsToShow); + if (typeof config?.maxRecentReportsToShow === 'number' && filteredWorkspaceChats && filteredWorkspaceChats?.length > config.maxRecentReportsToShow) { + filteredWorkspaceChats = filteredWorkspaceChats.slice(0, config.maxRecentReportsToShow); } const personalDetailsWithoutDMs = filteredPersonalDetailsOfRecentReports(filteredReports, filteredPersonalDetails); @@ -1846,7 +1845,7 @@ function filterAndOrderOptions(options: Options, searchInputValue: string, confi personalDetails: filteredPersonalDetails, userToInvite: filterResult.userToInvite, currentUserOption: filterResult.currentUserOption, - recentWorkspaceChats: filteredRecentWorkspaceChats, + workspaceChats: filteredWorkspaceChats, selfDMChat: options.selfDMChat, }; } diff --git a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx index 75e015f207ca..9c661fab2d1f 100644 --- a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx +++ b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx @@ -129,7 +129,7 @@ function MoneyRequestParticipantsSelector({participants = CONST.EMPTY_ARRAY, onF personalDetails: [], currentUserOption: null, headerMessage: '', - recentWorkspaceChats: [], + workspaceChats: [], selfDMChat: null, }; } @@ -168,8 +168,8 @@ function MoneyRequestParticipantsSelector({participants = CONST.EMPTY_ARRAY, onF newSections.push({ title: translate('workspace.common.workspace'), - data: chatOptions.recentWorkspaceChats ?? [], - shouldShow: (chatOptions.recentWorkspaceChats ?? []).length > 0, + data: chatOptions.workspaceChats ?? [], + shouldShow: (chatOptions.workspaceChats ?? []).length > 0, }); newSections.push({ title: translate('workspace.invoices.paymentMethods.personal'), @@ -219,7 +219,7 @@ function MoneyRequestParticipantsSelector({participants = CONST.EMPTY_ARRAY, onF chatOptions.recentReports, chatOptions.personalDetails, chatOptions.selfDMChat, - chatOptions.recentWorkspaceChats, + chatOptions.workspaceChats, chatOptions.userToInvite, personalDetails, translate, From 9e9e42843ee861895c962f3be0e664f39e39db53 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Tue, 17 Dec 2024 15:31:22 +0100 Subject: [PATCH 08/22] separate all workspace chats, not just recents --- src/libs/OptionsListUtils.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index d06f8e439906..57aef6edd37f 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -1209,6 +1209,12 @@ function getValidOptions( return true; }); + let workspaceChats: ReportUtils.OptionData[] = []; + + if (shouldSeparateWorkspaceChat) { + workspaceChats = allReportOptions.filter((option) => option.isPolicyExpenseChat); + } + const allPersonalDetailsOptions = includeP2P ? options.personalDetails.filter((detail) => !!detail?.login && !!detail.accountID && !detail?.isOptimisticPersonalDetail && (includeDomainEmail || !Str.isDomainEmail(detail.login))) : []; @@ -1319,11 +1325,9 @@ function getValidOptions( } const currentUserOption = allPersonalDetailsOptions.find((personalDetailsOption) => personalDetailsOption.login === currentUserLogin); - let workspaceChats: ReportUtils.OptionData[] = []; let selfDMChat: ReportUtils.OptionData | undefined; if (shouldSeparateWorkspaceChat) { - workspaceChats = recentReportOptions.filter((option) => option.isPolicyExpenseChat); recentReportOptions = recentReportOptions.filter((option) => !option.isPolicyExpenseChat); } if (shouldSeparateSelfDMChat) { From 9848008ff8f09db80c266545d01a5dc9d135e398 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Tue, 17 Dec 2024 16:18:17 +0100 Subject: [PATCH 09/22] filter selfDMChat option --- src/libs/OptionsListUtils.ts | 33 ++++++++++++++++++- .../MoneyRequestParticipantsSelector.tsx | 4 ++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index 57aef6edd37f..559b7f5b7788 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -1778,6 +1778,34 @@ function filterUserToInvite(options: Omit, searchValue: }); } +function filterSelfDMChat(report: ReportUtils.OptionData, searchTerms: string[]): ReportUtils.OptionData | undefined { + const isMatch = searchTerms.every((term) => { + const values: string[] = []; + + if (report.text) { + values.push(report.text); + } + if (report.login) { + values.push(report.login); + values.push(report.login.replace(CONST.EMAIL_SEARCH_REGEX, '')); + } + if (report.isThread) { + if (report.alternateText) { + values.push(report.alternateText); + } + } else if (!!report.isChatRoom || !!report.isPolicyExpenseChat) { + if (report.subtitle) { + values.push(report.subtitle); + } + } + + // Remove duplicate values and check if the term matches any value + return uniqFast(values).some((value) => value.includes(term)); + }); + + return isMatch ? report : undefined; +} + function filterOptions(options: Options, searchInputValue: string, config?: FilterUserToInviteConfig): Options { const parsedPhoneNumber = PhoneNumber.parsePhoneNumber(LoginUtils.appendCountryCode(Str.removeSMSDomain(searchInputValue))); const searchValue = parsedPhoneNumber.possible && parsedPhoneNumber.number?.e164 ? parsedPhoneNumber.number.e164 : searchInputValue.toLowerCase(); @@ -1797,12 +1825,15 @@ function filterOptions(options: Options, searchInputValue: string, config?: Filt ); const workspaceChats = filterWorkspaceChats(options.workspaceChats ?? [], searchTerms); + const selfDMChat = options.selfDMChat ? filterSelfDMChat(options.selfDMChat, searchTerms) : undefined; + return { personalDetails, recentReports, userToInvite, currentUserOption, workspaceChats, + selfDMChat, }; } @@ -1850,7 +1881,7 @@ function filterAndOrderOptions(options: Options, searchInputValue: string, confi userToInvite: filterResult.userToInvite, currentUserOption: filterResult.currentUserOption, workspaceChats: filteredWorkspaceChats, - selfDMChat: options.selfDMChat, + selfDMChat: filterResult.selfDMChat, }; } diff --git a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx index 9c661fab2d1f..aca33a3e40f7 100644 --- a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx +++ b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx @@ -32,6 +32,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {Participant} from '@src/types/onyx/IOU'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; type MoneyRequestParticipantsSelectorProps = { /** Callback to request parent modal to go to next step, which should be split */ @@ -204,7 +205,7 @@ function MoneyRequestParticipantsSelector({participants = CONST.EMPTY_ARRAY, onF } const headerMessage = OptionsListUtils.getHeaderMessage( - (chatOptions.personalDetails ?? []).length + (chatOptions.recentReports ?? []).length !== 0, + (chatOptions.personalDetails ?? []).length + (chatOptions.recentReports ?? []).length !== 0 || !isEmptyObject(chatOptions.selfDMChat), !!chatOptions?.userToInvite, debouncedSearchTerm.trim(), participants.some((participant) => OptionsListUtils.getPersonalDetailSearchTerms(participant).join(' ').toLowerCase().includes(cleanSearchTerm)), @@ -341,6 +342,7 @@ function MoneyRequestParticipantsSelector({participants = CONST.EMPTY_ARRAY, onF sections.forEach((section) => { length += section.data.length; }); + return length; }, [areOptionsInitialized, sections]); From efe51d48e5947837d9e9f97dd4ac56b09f11543e Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Tue, 17 Dec 2024 16:31:02 +0100 Subject: [PATCH 10/22] replace id fallbacks with CONST.DEFAULT_NUMBER_ID --- src/libs/OptionsListUtils.ts | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index 559b7f5b7788..535067ca134f 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -352,7 +352,7 @@ function isPersonalDetailsReady(personalDetails: OnyxEntry) * Get the participant option for a report. */ function getParticipantsOption(participant: ReportUtils.OptionData | Participant, personalDetails: OnyxEntry): Participant { - const detail = getPersonalDetailsForAccountIDs([participant.accountID ?? -1], personalDetails)[participant.accountID ?? -1]; + const detail = getPersonalDetailsForAccountIDs([participant.accountID ?? CONST.DEFAULT_NUMBER_ID], personalDetails)[participant.accountID ?? CONST.DEFAULT_NUMBER_ID]; // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const login = detail?.login || participant.login || ''; const displayName = LocalePhoneNumber.formatPhoneNumber(PersonalDetailsUtils.getDisplayNameOrDefault(detail, login || participant.text)); @@ -360,7 +360,7 @@ function getParticipantsOption(participant: ReportUtils.OptionData | Participant return { keyForList: String(detail?.accountID), login, - accountID: detail?.accountID ?? -1, + accountID: detail?.accountID ?? CONST.DEFAULT_NUMBER_ID, text: displayName, firstName: detail?.firstName ?? '', lastName: detail?.lastName ?? '', @@ -487,7 +487,7 @@ function getIOUReportIDOfLastAction(report: OnyxEntry): string | undefin * Get the last message text from the report directly or from other sources for special cases. */ function getLastMessageTextForReport(report: OnyxEntry, lastActorDetails: Partial | null, policy?: OnyxEntry): string { - const reportID = report?.reportID ?? '-1'; + const reportID = report?.reportID ?? CONST.DEFAULT_NUMBER_ID.toString(); const lastReportAction = lastVisibleReportActions[reportID] ?? null; // some types of actions are filtered out for lastReportAction, in some cases we need to check the actual last action @@ -521,7 +521,7 @@ function getLastMessageTextForReport(report: OnyxEntry, lastActorDetails lastMessageTextFromReport = ReportUtils.formatReportLastMessageText(properSchemaForMoneyRequestMessage); } else if (ReportActionUtils.isReportPreviewAction(lastReportAction)) { const iouReport = ReportUtils.getReportOrDraftReport(ReportActionUtils.getIOUReportIDFromReportActionPreview(lastReportAction)); - const lastIOUMoneyReportAction = allSortedReportActions[iouReport?.reportID ?? '-1']?.find( + const lastIOUMoneyReportAction = allSortedReportActions[iouReport?.reportID ?? CONST.DEFAULT_NUMBER_ID]?.find( (reportAction, key): reportAction is ReportAction => ReportActionUtils.shouldReportActionBeVisible(reportAction, key, ReportUtils.canUserPerformWriteAction(report)) && reportAction.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE && @@ -543,7 +543,7 @@ function getLastMessageTextForReport(report: OnyxEntry, lastActorDetails lastMessageTextFromReport = ReportUtils.getReimbursementDeQueuedActionMessage(lastReportAction, report, true); } else if (ReportActionUtils.isDeletedParentAction(lastReportAction) && ReportUtils.isChatReport(report)) { lastMessageTextFromReport = ReportUtils.getDeletedParentActionMessageForChatReport(lastReportAction); - } else if (ReportActionUtils.isPendingRemove(lastReportAction) && ReportActionUtils.isThreadParentMessage(lastReportAction, report?.reportID ?? '-1')) { + } else if (ReportActionUtils.isPendingRemove(lastReportAction) && ReportActionUtils.isThreadParentMessage(lastReportAction, report?.reportID ?? CONST.DEFAULT_NUMBER_ID.toString())) { lastMessageTextFromReport = Localize.translateLocal('parentReportAction.hiddenMessage'); } else if (ReportUtils.isReportMessageAttachment({text: report?.lastMessageText ?? '-1', html: report?.lastMessageHtml, translationKey: report?.lastMessageTranslationKey, type: ''})) { // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing @@ -686,7 +686,7 @@ function createOption( hasMultipleParticipants = personalDetailList.length > 1 || result.isChatRoom || result.isPolicyExpenseChat || ReportUtils.isGroupChat(report); subtitle = ReportUtils.getChatRoomSubtitle(report); - const lastActorDetails = personalDetailMap[report.lastActorAccountID ?? -1] ?? null; + const lastActorDetails = personalDetailMap[report.lastActorAccountID ?? CONST.DEFAULT_NUMBER_ID] ?? null; const lastActorDisplayName = getLastActorDisplayName(lastActorDetails, hasMultipleParticipants); const lastMessageTextFromReport = getLastMessageTextForReport(report, lastActorDetails); let lastMessageText = lastMessageTextFromReport; @@ -901,7 +901,13 @@ function createOptionList(personalDetails: OnyxEntry, repor const allPersonalDetailsOptions = Object.values(personalDetails ?? {}).map((personalDetail) => ({ item: personalDetail, - ...createOption([personalDetail?.accountID ?? -1], personalDetails, reportMapForAccountIDs[personalDetail?.accountID ?? -1], {}, {showPersonalDetails: true}), + ...createOption( + [personalDetail?.accountID ?? CONST.DEFAULT_NUMBER_ID], + personalDetails, + reportMapForAccountIDs[personalDetail?.accountID ?? CONST.DEFAULT_NUMBER_ID], + {}, + {showPersonalDetails: true}, + ), })); return { @@ -1136,7 +1142,7 @@ function getValidOptions( shouldSeparateWorkspaceChat = false, }: GetOptionsConfig = {}, ): Options { - const topmostReportId = Navigation.getTopmostReportId() ?? '-1'; + const topmostReportId = Navigation.getTopmostReportId() ?? CONST.DEFAULT_NUMBER_ID.toString(); // Filter out all the reports that shouldn't be displayed const filteredReportOptions = options.reports.filter((option) => { @@ -1407,8 +1413,8 @@ function getIOUConfirmationOptionsFromPayeePersonalDetail(personalDetail: OnyxEn ], descriptiveText: amountText ?? '', login: personalDetail?.login ?? '', - accountID: personalDetail?.accountID ?? -1, - keyForList: String(personalDetail?.accountID ?? -1), + accountID: personalDetail?.accountID ?? CONST.DEFAULT_NUMBER_ID, + keyForList: String(personalDetail?.accountID ?? CONST.DEFAULT_NUMBER_ID), }; } @@ -1486,14 +1492,14 @@ function formatMemberForList(member: ReportUtils.OptionData): MemberForList { // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing alternateText: member.alternateText || member.login || '', // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - keyForList: member.keyForList || String(accountID ?? -1) || '', + keyForList: member.keyForList || String(accountID ?? CONST.DEFAULT_NUMBER_ID) || '', isSelected: member.isSelected ?? false, isDisabled: member.isDisabled ?? false, accountID, login: member.login ?? '', icons: member.icons, pendingAction: member.pendingAction, - reportID: member.reportID ?? '-1', + reportID: member.reportID ?? String(CONST.DEFAULT_NUMBER_ID), }; } From 398feac05076e32f0fd59e810ac96ef76c1637eb Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Tue, 17 Dec 2024 16:48:32 +0100 Subject: [PATCH 11/22] fix ids rule --- src/components/MoneyRequestConfirmationList.tsx | 12 ++++++------ src/libs/OptionsListUtils.ts | 17 ++++++++++++----- .../MoneyRequestParticipantsSelector.tsx | 8 ++++++-- .../request/step/IOURequestStepParticipants.tsx | 4 ++-- 4 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index e1516a5918e7..182d1c815500 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -202,16 +202,16 @@ function MoneyRequestConfirmationList({ const isTypeInvoice = iouType === CONST.IOU.TYPE.INVOICE; const isScanRequest = useMemo(() => TransactionUtils.isScanRequest(transaction), [transaction]); - const transactionID = transaction?.transactionID ?? CONST.DEFAULT_NUMBER_ID.toString(); - const customUnitRateID = TransactionUtils.getRateID(transaction) ?? CONST.DEFAULT_NUMBER_ID.toString(); + const transactionID = transaction?.transactionID ?? String(CONST.DEFAULT_NUMBER_ID); + const customUnitRateID = TransactionUtils.getRateID(transaction) ?? String(CONST.DEFAULT_NUMBER_ID); useEffect(() => { if ((customUnitRateID && customUnitRateID !== '0') || !isDistanceRequest) { return; } - const defaultRate = defaultMileageRate?.customUnitRateID ?? ''; - const lastSelectedRate = lastSelectedDistanceRates?.[policy?.id ?? ''] ?? defaultRate; + const defaultRate = defaultMileageRate?.customUnitRateID ?? String(CONST.DEFAULT_NUMBER_ID); + const lastSelectedRate = lastSelectedDistanceRates?.[policy?.id ?? String(CONST.DEFAULT_NUMBER_ID)] ?? defaultRate; const rateID = lastSelectedRate; IOU.setCustomUnitRateID(transactionID, rateID); }, [defaultMileageRate, customUnitRateID, lastSelectedDistanceRates, policy?.id, transactionID, isDistanceRequest]); @@ -373,7 +373,7 @@ function MoneyRequestConfirmationList({ let taxCode: string; if (isDistanceRequest) { const customUnitRate = getDistanceRateCustomUnitRate(policy, customUnitRateID); - taxCode = customUnitRate?.attributes?.taxRateExternalID ?? ''; + taxCode = customUnitRate?.attributes?.taxRateExternalID ?? String(CONST.DEFAULT_NUMBER_ID); taxableAmount = DistanceRequestUtils.getTaxableAmount(policy, customUnitRateID, distance); } else { taxableAmount = transaction.amount ?? 0; @@ -382,7 +382,7 @@ function MoneyRequestConfirmationList({ const taxPercentage = TransactionUtils.getTaxValue(policy, transaction, taxCode) ?? ''; const taxAmount = TransactionUtils.calculateTaxAmount(taxPercentage, taxableAmount, transaction.currency); const taxAmountInSmallestCurrencyUnits = CurrencyUtils.convertToBackendAmount(Number.parseFloat(taxAmount.toString())); - IOU.setMoneyRequestTaxAmount(transaction.transactionID ?? '', taxAmountInSmallestCurrencyUnits); + IOU.setMoneyRequestTaxAmount(transaction.transactionID ?? String(CONST.DEFAULT_NUMBER_ID), taxAmountInSmallestCurrencyUnits); }, [ policy, shouldShowTax, diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index 535067ca134f..abf381f2d3a1 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -487,7 +487,7 @@ function getIOUReportIDOfLastAction(report: OnyxEntry): string | undefin * Get the last message text from the report directly or from other sources for special cases. */ function getLastMessageTextForReport(report: OnyxEntry, lastActorDetails: Partial | null, policy?: OnyxEntry): string { - const reportID = report?.reportID ?? CONST.DEFAULT_NUMBER_ID.toString(); + const reportID = report?.reportID ?? String(CONST.DEFAULT_NUMBER_ID); const lastReportAction = lastVisibleReportActions[reportID] ?? null; // some types of actions are filtered out for lastReportAction, in some cases we need to check the actual last action @@ -543,9 +543,16 @@ function getLastMessageTextForReport(report: OnyxEntry, lastActorDetails lastMessageTextFromReport = ReportUtils.getReimbursementDeQueuedActionMessage(lastReportAction, report, true); } else if (ReportActionUtils.isDeletedParentAction(lastReportAction) && ReportUtils.isChatReport(report)) { lastMessageTextFromReport = ReportUtils.getDeletedParentActionMessageForChatReport(lastReportAction); - } else if (ReportActionUtils.isPendingRemove(lastReportAction) && ReportActionUtils.isThreadParentMessage(lastReportAction, report?.reportID ?? CONST.DEFAULT_NUMBER_ID.toString())) { + } else if (ReportActionUtils.isPendingRemove(lastReportAction) && ReportActionUtils.isThreadParentMessage(lastReportAction, report?.reportID ?? String(CONST.DEFAULT_NUMBER_ID))) { lastMessageTextFromReport = Localize.translateLocal('parentReportAction.hiddenMessage'); - } else if (ReportUtils.isReportMessageAttachment({text: report?.lastMessageText ?? '-1', html: report?.lastMessageHtml, translationKey: report?.lastMessageTranslationKey, type: ''})) { + } else if ( + ReportUtils.isReportMessageAttachment({ + text: report?.lastMessageText ?? String(CONST.DEFAULT_NUMBER_ID), + html: report?.lastMessageHtml, + translationKey: report?.lastMessageTranslationKey, + type: '', + }) + ) { // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing lastMessageTextFromReport = `[${Localize.translateLocal((report?.lastMessageTranslationKey || 'common.attachment') as TranslationPaths)}]`; } else if (ReportActionUtils.isModifiedExpenseAction(lastReportAction)) { @@ -1142,7 +1149,7 @@ function getValidOptions( shouldSeparateWorkspaceChat = false, }: GetOptionsConfig = {}, ): Options { - const topmostReportId = Navigation.getTopmostReportId() ?? CONST.DEFAULT_NUMBER_ID.toString(); + const topmostReportId = Navigation.getTopmostReportId() ?? String(CONST.DEFAULT_NUMBER_ID); // Filter out all the reports that shouldn't be displayed const filteredReportOptions = options.reports.filter((option) => { @@ -1262,7 +1269,7 @@ function getValidOptions( const shouldShowInvoiceRoom = includeInvoiceRooms && ReportUtils.isInvoiceRoom(reportOption.item) && - ReportUtils.isPolicyAdmin(reportOption.policyID ?? '', policies) && + ReportUtils.isPolicyAdmin(reportOption.policyID ?? String(CONST.DEFAULT_NUMBER_ID), policies) && !reportOption.private_isArchived && PolicyUtils.canSendInvoiceFromWorkspace(reportOption.policyID); diff --git a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx index aca33a3e40f7..b4210af14382 100644 --- a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx +++ b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx @@ -158,7 +158,7 @@ function MoneyRequestParticipantsSelector({participants = CONST.EMPTY_ARRAY, onF const formatResults = OptionsListUtils.formatSectionsFromSearchTerm( debouncedSearchTerm, - participants.map((participant) => ({...participant, reportID: participant.reportID ?? '-1'})), + participants.map((participant) => ({...participant, reportID: participant.reportID ?? String(CONST.DEFAULT_NUMBER_ID)})), chatOptions.recentReports, chatOptions.personalDetails, personalDetails, @@ -192,7 +192,11 @@ function MoneyRequestParticipantsSelector({participants = CONST.EMPTY_ARRAY, onF if ( chatOptions.userToInvite && - !OptionsListUtils.isCurrentUser({...chatOptions.userToInvite, accountID: chatOptions.userToInvite?.accountID ?? -1, status: chatOptions.userToInvite?.status ?? undefined}) + !OptionsListUtils.isCurrentUser({ + ...chatOptions.userToInvite, + accountID: chatOptions.userToInvite?.accountID ?? CONST.DEFAULT_NUMBER_ID, + status: chatOptions.userToInvite?.status ?? undefined, + }) ) { newSections.push({ title: undefined, diff --git a/src/pages/iou/request/step/IOURequestStepParticipants.tsx b/src/pages/iou/request/step/IOURequestStepParticipants.tsx index 95e0e3ffd693..d2a50f40ac49 100644 --- a/src/pages/iou/request/step/IOURequestStepParticipants.tsx +++ b/src/pages/iou/request/step/IOURequestStepParticipants.tsx @@ -37,7 +37,7 @@ function IOURequestStepParticipants({ const {translate} = useLocalize(); const styles = useThemeStyles(); const isFocused = useIsFocused(); - const [skipConfirmation] = useOnyx(`${ONYXKEYS.COLLECTION.SKIP_CONFIRMATION}${transactionID ?? -1}`); + const [skipConfirmation] = useOnyx(`${ONYXKEYS.COLLECTION.SKIP_CONFIRMATION}${transactionID ?? CONST.DEFAULT_NUMBER_ID}`); // We need to set selectedReportID if user has navigated back from confirmation page and navigates to confirmation page with already selected participant const selectedReportID = useRef(participants?.length === 1 ? participants.at(0)?.reportID ?? reportID : reportID); @@ -105,7 +105,7 @@ function IOURequestStepParticipants({ return; } - const firstParticipantReportID = val.at(0)?.reportID ?? ''; + const firstParticipantReportID = val.at(0)?.reportID ?? String(CONST.DEFAULT_NUMBER_ID); const rateID = DistanceRequestUtils.getCustomUnitRateID(firstParticipantReportID); const isInvoice = iouType === CONST.IOU.TYPE.INVOICE && ReportUtils.isInvoiceRoomWithID(firstParticipantReportID); numberOfParticipants.current = val.length; From 0bf0562b185a4a803ab9232dc6e83c87a58ac37a Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Thu, 19 Dec 2024 14:47:08 +0100 Subject: [PATCH 12/22] export getReport from ReportUtils --- src/libs/ReportUtils.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 6bffaca697c7..a448fd6b89d9 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -8834,6 +8834,7 @@ export { getAllReportActionsErrorsAndReportActionThatRequiresAttention, hasInvoiceReports, getReportMetadata, + getReport, }; export type { From 53adb31be7e445fba013ebf21b12d7d72d2d9ade Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Thu, 19 Dec 2024 15:32:10 +0100 Subject: [PATCH 13/22] simplify workspace filtering, fix no results found condition --- src/libs/OptionsListUtils.ts | 13 ------------- .../request/MoneyRequestParticipantsSelector.tsx | 14 ++++++++++++-- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index 6a43f7e5aefb..330063122925 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -1832,19 +1832,6 @@ function filterWorkspaceChats(reports: ReportUtils.OptionData[], searchTerms: st if (item.text) { values.push(item.text); } - if (item.login) { - values.push(item.login); - values.push(item.login.replace(CONST.EMAIL_SEARCH_REGEX, '')); - } - if (item.isThread) { - if (item.alternateText) { - values.push(item.alternateText); - } - } else if (!!item.isChatRoom || !!item.isPolicyExpenseChat) { - if (item.subtitle) { - values.push(item.subtitle); - } - } return uniqFast(values); }), // We start from all unfiltered reports: diff --git a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx index 5b9843939879..70ad7178b740 100644 --- a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx +++ b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx @@ -167,12 +167,22 @@ function MoneyRequestParticipantsSelector({participants = CONST.EMPTY_ARRAY, onF const inputHelperText = useMemo( () => OptionsListUtils.getHeaderMessage( - (chatOptions.personalDetails ?? []).length + (chatOptions.recentReports ?? []).length !== 0 || !isEmptyObject(chatOptions.selfDMChat), + (chatOptions.personalDetails ?? []).length + (chatOptions.recentReports ?? []).length + (chatOptions.workspaceChats ?? []).length !== 0 || + !isEmptyObject(chatOptions.selfDMChat), !!chatOptions?.userToInvite, debouncedSearchTerm.trim(), participants.some((participant) => OptionsListUtils.getPersonalDetailSearchTerms(participant).join(' ').toLowerCase().includes(cleanSearchTerm)), ), - [chatOptions.personalDetails, chatOptions.recentReports, chatOptions.selfDMChat, chatOptions?.userToInvite, cleanSearchTerm, debouncedSearchTerm, participants], + [ + chatOptions.personalDetails, + chatOptions.recentReports, + chatOptions.selfDMChat, + chatOptions?.userToInvite, + chatOptions.workspaceChats, + cleanSearchTerm, + debouncedSearchTerm, + participants, + ], ); /** * Returns the sections needed for the OptionsSelector From e1447e9f4ea01d5d59c5411f87c34a35e830f14c Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Fri, 20 Dec 2024 10:19:15 +0100 Subject: [PATCH 14/22] replace isPolicyExpenseChat with isOwnPolicyExpenseChat --- src/libs/OptionsListUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index da6e91717eb4..54109eee2c1c 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -1338,7 +1338,7 @@ function getValidOptions( let workspaceChats: ReportUtils.OptionData[] = []; if (shouldSeparateWorkspaceChat) { - workspaceChats = allReportOptions.filter((option) => option.isPolicyExpenseChat); + workspaceChats = allReportOptions.filter((option) => option.isOwnPolicyExpenseChat); } const allPersonalDetailsOptions = includeP2P From d56d865c47737823a31819b93537528718901fdd Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Fri, 20 Dec 2024 13:53:31 +0100 Subject: [PATCH 15/22] remove ReportUtils.getReport references --- src/libs/ReportUtils.ts | 1 - src/pages/iou/request/step/IOURequestStepParticipants.tsx | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 0a994b7c0dfe..c20ec7386b0a 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -8869,7 +8869,6 @@ export { getAllReportActionsErrorsAndReportActionThatRequiresAttention, hasInvoiceReports, getReportMetadata, - getReport, isHiddenForCurrentUser, }; diff --git a/src/pages/iou/request/step/IOURequestStepParticipants.tsx b/src/pages/iou/request/step/IOURequestStepParticipants.tsx index d2a50f40ac49..6fa82e43c988 100644 --- a/src/pages/iou/request/step/IOURequestStepParticipants.tsx +++ b/src/pages/iou/request/step/IOURequestStepParticipants.tsx @@ -64,6 +64,7 @@ function IOURequestStepParticipants({ }, [iouType, translate, isSplitRequest, action]); const selfDMReportID = useMemo(() => ReportUtils.findSelfDMReportID(), []); + const [selfDMReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${selfDMReportID}`); const receiptFilename = transaction?.filename; const receiptPath = transaction?.receipt?.source; @@ -89,10 +90,10 @@ function IOURequestStepParticipants({ const rateID = DistanceRequestUtils.getCustomUnitRateID(selfDMReportID); IOU.setCustomUnitRateID(transactionID, rateID); - IOU.setMoneyRequestParticipantsFromReport(transactionID, ReportUtils.getReport(selfDMReportID)); + IOU.setMoneyRequestParticipantsFromReport(transactionID, selfDMReport); const iouConfirmationPageRoute = ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(action, CONST.IOU.TYPE.TRACK, transactionID, selfDMReportID); Navigation.navigate(iouConfirmationPageRoute); - }, [action, selfDMReportID, transactionID]); + }, [action, selfDMReport, selfDMReportID, transactionID]); const addParticipant = useCallback( (val: Participant[]) => { From 5f6ffce3470a90d15b7e9c73af3e31632fdff370 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Fri, 20 Dec 2024 14:03:50 +0100 Subject: [PATCH 16/22] filter out archived workspaces --- src/libs/OptionsListUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index 54109eee2c1c..66709c9a6038 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -1338,7 +1338,7 @@ function getValidOptions( let workspaceChats: ReportUtils.OptionData[] = []; if (shouldSeparateWorkspaceChat) { - workspaceChats = allReportOptions.filter((option) => option.isOwnPolicyExpenseChat); + workspaceChats = allReportOptions.filter((option) => option.isOwnPolicyExpenseChat && !option.private_isArchived); } const allPersonalDetailsOptions = includeP2P From f246b59ee93305bc45c3bfe1336b008627fa621b Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Fri, 20 Dec 2024 21:33:25 +0100 Subject: [PATCH 17/22] remove limit of displayed workspaces --- src/libs/OptionsListUtils.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index 630ee1363947..c337b9f74385 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -1860,7 +1860,7 @@ function filterAndOrderOptions(options: Options, searchInputValue: string, confi filterResult = filterOptions(options, searchInputValue, config); } - let {recentReports: filteredReports, personalDetails: filteredPersonalDetails, workspaceChats: filteredWorkspaceChats} = filterResult; + let {recentReports: filteredReports, personalDetails: filteredPersonalDetails} = filterResult; // on staging server, in specific cases (see issue) BE returns duplicated personalDetails entries filteredPersonalDetails = filteredPersonalDetails.filter((detail, index, array) => array.findIndex((i) => i.login === detail.login) === index); @@ -1870,10 +1870,6 @@ function filterAndOrderOptions(options: Options, searchInputValue: string, confi filteredReports = filteredReports.slice(0, config.maxRecentReportsToShow); } - if (typeof config?.maxRecentReportsToShow === 'number' && filteredWorkspaceChats && filteredWorkspaceChats?.length > config.maxRecentReportsToShow) { - filteredWorkspaceChats = filteredWorkspaceChats.slice(0, config.maxRecentReportsToShow); - } - const personalDetailsWithoutDMs = filteredPersonalDetailsOfRecentReports(filteredReports, filteredPersonalDetails); const orderedPersonalDetails = orderPersonalDetailsOptions(personalDetailsWithoutDMs); @@ -1892,7 +1888,7 @@ function filterAndOrderOptions(options: Options, searchInputValue: string, confi personalDetails: filteredPersonalDetails, userToInvite: filterResult.userToInvite, currentUserOption: filterResult.currentUserOption, - workspaceChats: filteredWorkspaceChats, + workspaceChats: filterResult.workspaceChats, selfDMChat: filterResult.selfDMChat, }; } From 6a6207d93636d11770481c941c8546a63c9bb1bf Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Fri, 27 Dec 2024 15:38:37 +0100 Subject: [PATCH 18/22] fix id fallbacks --- src/libs/OptionsListUtils.ts | 19 ++++++++++++++----- src/libs/ReportActionsUtils.ts | 2 +- src/libs/ReportUtils.ts | 4 ++-- .../MoneyRequestParticipantsSelector.tsx | 2 +- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index 0967d9e22423..8dbb55096483 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -506,7 +506,12 @@ function getIOUReportIDOfLastAction(report: OnyxEntry): string | undefin * Get the last message text from the report directly or from other sources for special cases. */ function getLastMessageTextForReport(report: OnyxEntry, lastActorDetails: Partial | null, policy?: OnyxEntry): string { - const reportID = report?.reportID ?? String(CONST.DEFAULT_NUMBER_ID); + const reportID = report?.reportID; + + if (!reportID) { + return ''; + } + const lastReportAction = lastVisibleReportActions[reportID] ?? null; // some types of actions are filtered out for lastReportAction, in some cases we need to check the actual last action @@ -562,7 +567,7 @@ function getLastMessageTextForReport(report: OnyxEntry, lastActorDetails lastMessageTextFromReport = ReportUtils.getReimbursementDeQueuedActionMessage(lastReportAction, report, true); } else if (ReportActionUtils.isDeletedParentAction(lastReportAction) && ReportUtils.isChatReport(report)) { lastMessageTextFromReport = ReportUtils.getDeletedParentActionMessageForChatReport(lastReportAction); - } else if (ReportActionUtils.isPendingRemove(lastReportAction) && ReportActionUtils.isThreadParentMessage(lastReportAction, report?.reportID ?? String(CONST.DEFAULT_NUMBER_ID))) { + } else if (ReportActionUtils.isPendingRemove(lastReportAction) && ReportActionUtils.isThreadParentMessage(lastReportAction, report?.reportID)) { lastMessageTextFromReport = Localize.translateLocal('parentReportAction.hiddenMessage'); } else if (ReportUtils.isReportMessageAttachment({text: report?.lastMessageText ?? '-1', html: report?.lastMessageHtml, type: ''})) { lastMessageTextFromReport = `[${Localize.translateLocal('common.attachment')}]`; @@ -1173,7 +1178,7 @@ function getValidOptions( shouldSeparateWorkspaceChat = false, }: GetOptionsConfig = {}, ): Options { - const topmostReportId = Navigation.getTopmostReportId() ?? String(CONST.DEFAULT_NUMBER_ID); + const topmostReportId = Navigation.getTopmostReportId(); // Filter out all the reports that shouldn't be displayed const filteredReportOptions = options.reports.filter((option) => { @@ -1290,10 +1295,14 @@ function getValidOptions( const isCurrentUserOwnedPolicyExpenseChatThatCouldShow = reportOption.isPolicyExpenseChat && reportOption.ownerAccountID === currentUserAccountID && includeOwnedWorkspaceChats && !reportOption.private_isArchived; + if (!reportOption.policyID) { + break; + } + const shouldShowInvoiceRoom = includeInvoiceRooms && ReportUtils.isInvoiceRoom(reportOption.item) && - ReportUtils.isPolicyAdmin(reportOption.policyID ?? String(CONST.DEFAULT_NUMBER_ID), policies) && + ReportUtils.isPolicyAdmin(reportOption.policyID, policies) && !reportOption.private_isArchived && PolicyUtils.canSendInvoiceFromWorkspace(reportOption.policyID); @@ -1530,7 +1539,7 @@ function formatMemberForList(member: ReportUtils.OptionData): MemberForList { login: member.login ?? '', icons: member.icons, pendingAction: member.pendingAction, - reportID: member.reportID ?? String(CONST.DEFAULT_NUMBER_ID), + reportID: member.reportID, }; } diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index 4fa704944bc9..f659f70f552e 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -347,7 +347,7 @@ function isInviteOrRemovedAction( /** * Returns whether the comment is a thread parent message/the first message in a thread */ -function isThreadParentMessage(reportAction: OnyxEntry, reportID: string): boolean { +function isThreadParentMessage(reportAction: OnyxEntry, reportID?: string): boolean { const {childType, childVisibleActionCount = 0, childReportID} = reportAction ?? {}; return childType === CONST.REPORT.TYPE.CHAT && (childVisibleActionCount > 0 || String(childReportID) === reportID); } diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 027b11c516f1..60c3b7d9aae1 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -6409,7 +6409,7 @@ function isReportNotFound(report: OnyxEntry): boolean { /** * Check if the report is the parent report of the currently viewed report or at least one child report has report action */ -function shouldHideReport(report: OnyxEntry, currentReportId: string): boolean { +function shouldHideReport(report: OnyxEntry, currentReportId?: string): boolean { const currentReport = getReportOrDraftReport(currentReportId); const parentReport = getParentReport(!isEmptyObject(currentReport) ? currentReport : undefined); const reportActions = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report?.reportID}`] ?? {}; @@ -6579,7 +6579,7 @@ function hasReportErrorsOtherThanFailedReceipt(report: Report, doesReportHaveVio type ShouldReportBeInOptionListParams = { report: OnyxEntry; - currentReportId: string; + currentReportId?: string; isInFocusMode: boolean; betas: OnyxEntry; policies: OnyxCollection; diff --git a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx index 3962f79599d1..ba3efa7d10da 100644 --- a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx +++ b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx @@ -158,7 +158,7 @@ function MoneyRequestParticipantsSelector({participants = CONST.EMPTY_ARRAY, onF const formatResults = OptionsListUtils.formatSectionsFromSearchTerm( debouncedSearchTerm, - participants.map((participant) => ({...participant, reportID: participant.reportID ?? String(CONST.DEFAULT_NUMBER_ID)})), + participants.map((participant) => ({...participant, reportID: participant.reportID ?? ''})), chatOptions.recentReports, chatOptions.personalDetails, personalDetails, From 9f49eeda8e263f4157d958446e8845406c243732 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Fri, 27 Dec 2024 16:04:48 +0100 Subject: [PATCH 19/22] fix id fallback in MoneyRequestParticipantsSelector --- src/pages/iou/request/MoneyRequestParticipantsSelector.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx index ba3efa7d10da..dfa0d7f37b8b 100644 --- a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx +++ b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx @@ -158,7 +158,7 @@ function MoneyRequestParticipantsSelector({participants = CONST.EMPTY_ARRAY, onF const formatResults = OptionsListUtils.formatSectionsFromSearchTerm( debouncedSearchTerm, - participants.map((participant) => ({...participant, reportID: participant.reportID ?? ''})), + participants.map((participant) => ({...participant, reportID: participant.reportID})) as ReportUtils.OptionData[], chatOptions.recentReports, chatOptions.personalDetails, personalDetails, From eee9a5b3e48acc1bbe5b541e6c1ab783a171a242 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Mon, 30 Dec 2024 12:47:52 +0100 Subject: [PATCH 20/22] revert ID fallback changes in OptionsListUtils.ts --- src/libs/OptionsListUtils.ts | 40 ++++++++++++------------------------ 1 file changed, 13 insertions(+), 27 deletions(-) diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index 8dbb55096483..ec719e7ba6ac 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -371,7 +371,7 @@ function isPersonalDetailsReady(personalDetails: OnyxEntry) * Get the participant option for a report. */ function getParticipantsOption(participant: ReportUtils.OptionData | Participant, personalDetails: OnyxEntry): Participant { - const detail = getPersonalDetailsForAccountIDs([participant.accountID ?? CONST.DEFAULT_NUMBER_ID], personalDetails)[participant.accountID ?? CONST.DEFAULT_NUMBER_ID]; + const detail = getPersonalDetailsForAccountIDs([participant.accountID ?? -1], personalDetails)[participant.accountID ?? -1]; // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const login = detail?.login || participant.login || ''; const displayName = LocalePhoneNumber.formatPhoneNumber(PersonalDetailsUtils.getDisplayNameOrDefault(detail, login || participant.text)); @@ -379,7 +379,7 @@ function getParticipantsOption(participant: ReportUtils.OptionData | Participant return { keyForList: String(detail?.accountID), login, - accountID: detail?.accountID ?? CONST.DEFAULT_NUMBER_ID, + accountID: detail?.accountID ?? -1, text: displayName, firstName: detail?.firstName ?? '', lastName: detail?.lastName ?? '', @@ -506,11 +506,7 @@ function getIOUReportIDOfLastAction(report: OnyxEntry): string | undefin * Get the last message text from the report directly or from other sources for special cases. */ function getLastMessageTextForReport(report: OnyxEntry, lastActorDetails: Partial | null, policy?: OnyxEntry): string { - const reportID = report?.reportID; - - if (!reportID) { - return ''; - } + const reportID = report?.reportID ?? '-1'; const lastReportAction = lastVisibleReportActions[reportID] ?? null; @@ -545,7 +541,7 @@ function getLastMessageTextForReport(report: OnyxEntry, lastActorDetails lastMessageTextFromReport = ReportUtils.formatReportLastMessageText(properSchemaForMoneyRequestMessage); } else if (ReportActionUtils.isReportPreviewAction(lastReportAction)) { const iouReport = ReportUtils.getReportOrDraftReport(ReportActionUtils.getIOUReportIDFromReportActionPreview(lastReportAction)); - const lastIOUMoneyReportAction = allSortedReportActions[iouReport?.reportID ?? CONST.DEFAULT_NUMBER_ID]?.find( + const lastIOUMoneyReportAction = allSortedReportActions[iouReport?.reportID ?? '-1']?.find( (reportAction, key): reportAction is ReportAction => ReportActionUtils.shouldReportActionBeVisible(reportAction, key, ReportUtils.canUserPerformWriteAction(report)) && reportAction.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE && @@ -567,7 +563,7 @@ function getLastMessageTextForReport(report: OnyxEntry, lastActorDetails lastMessageTextFromReport = ReportUtils.getReimbursementDeQueuedActionMessage(lastReportAction, report, true); } else if (ReportActionUtils.isDeletedParentAction(lastReportAction) && ReportUtils.isChatReport(report)) { lastMessageTextFromReport = ReportUtils.getDeletedParentActionMessageForChatReport(lastReportAction); - } else if (ReportActionUtils.isPendingRemove(lastReportAction) && ReportActionUtils.isThreadParentMessage(lastReportAction, report?.reportID)) { + } else if (ReportActionUtils.isPendingRemove(lastReportAction) && ReportActionUtils.isThreadParentMessage(lastReportAction, report?.reportID ?? '-1')) { lastMessageTextFromReport = Localize.translateLocal('parentReportAction.hiddenMessage'); } else if (ReportUtils.isReportMessageAttachment({text: report?.lastMessageText ?? '-1', html: report?.lastMessageHtml, type: ''})) { lastMessageTextFromReport = `[${Localize.translateLocal('common.attachment')}]`; @@ -709,7 +705,7 @@ function createOption( hasMultipleParticipants = personalDetailList.length > 1 || result.isChatRoom || result.isPolicyExpenseChat || ReportUtils.isGroupChat(report); subtitle = ReportUtils.getChatRoomSubtitle(report); - const lastActorDetails = personalDetailMap[report.lastActorAccountID ?? CONST.DEFAULT_NUMBER_ID] ?? null; + const lastActorDetails = personalDetailMap[report.lastActorAccountID ?? -1] ?? null; const lastActorDisplayName = getLastActorDisplayName(lastActorDetails, hasMultipleParticipants); const lastMessageTextFromReport = getLastMessageTextForReport(report, lastActorDetails); let lastMessageText = lastMessageTextFromReport; @@ -924,13 +920,7 @@ function createOptionList(personalDetails: OnyxEntry, repor const allPersonalDetailsOptions = Object.values(personalDetails ?? {}).map((personalDetail) => ({ item: personalDetail, - ...createOption( - [personalDetail?.accountID ?? CONST.DEFAULT_NUMBER_ID], - personalDetails, - reportMapForAccountIDs[personalDetail?.accountID ?? CONST.DEFAULT_NUMBER_ID], - {}, - {showPersonalDetails: true}, - ), + ...createOption([personalDetail?.accountID ?? -1], personalDetails, reportMapForAccountIDs[personalDetail?.accountID ?? -1], {}, {showPersonalDetails: true}), })); return { @@ -1178,7 +1168,7 @@ function getValidOptions( shouldSeparateWorkspaceChat = false, }: GetOptionsConfig = {}, ): Options { - const topmostReportId = Navigation.getTopmostReportId(); + const topmostReportId = Navigation.getTopmostReportId() ?? '-1'; // Filter out all the reports that shouldn't be displayed const filteredReportOptions = options.reports.filter((option) => { @@ -1295,14 +1285,10 @@ function getValidOptions( const isCurrentUserOwnedPolicyExpenseChatThatCouldShow = reportOption.isPolicyExpenseChat && reportOption.ownerAccountID === currentUserAccountID && includeOwnedWorkspaceChats && !reportOption.private_isArchived; - if (!reportOption.policyID) { - break; - } - const shouldShowInvoiceRoom = includeInvoiceRooms && ReportUtils.isInvoiceRoom(reportOption.item) && - ReportUtils.isPolicyAdmin(reportOption.policyID, policies) && + ReportUtils.isPolicyAdmin(reportOption.policyID ?? '', policies) && !reportOption.private_isArchived && PolicyUtils.canSendInvoiceFromWorkspace(reportOption.policyID); @@ -1453,8 +1439,8 @@ function getIOUConfirmationOptionsFromPayeePersonalDetail(personalDetail: OnyxEn ], descriptiveText: amountText ?? '', login: personalDetail?.login ?? '', - accountID: personalDetail?.accountID ?? CONST.DEFAULT_NUMBER_ID, - keyForList: String(personalDetail?.accountID ?? CONST.DEFAULT_NUMBER_ID), + accountID: personalDetail?.accountID ?? -1, + keyForList: String(personalDetail?.accountID ?? -1), }; } @@ -1532,14 +1518,14 @@ function formatMemberForList(member: ReportUtils.OptionData): MemberForList { // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing alternateText: member.alternateText || member.login || '', // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - keyForList: member.keyForList || String(accountID ?? CONST.DEFAULT_NUMBER_ID) || '', + keyForList: member.keyForList || String(accountID ?? -1) || '', isSelected: member.isSelected ?? false, isDisabled: member.isDisabled ?? false, accountID, login: member.login ?? '', icons: member.icons, pendingAction: member.pendingAction, - reportID: member.reportID, + reportID: member.reportID ?? '-1', }; } From ad595ece15e4587dbe2945ee02d3317725a1208a Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Mon, 30 Dec 2024 13:41:37 +0100 Subject: [PATCH 21/22] remove unnecessary empty line --- src/libs/OptionsListUtils.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index ec719e7ba6ac..9d391172e537 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -507,7 +507,6 @@ function getIOUReportIDOfLastAction(report: OnyxEntry): string | undefin */ function getLastMessageTextForReport(report: OnyxEntry, lastActorDetails: Partial | null, policy?: OnyxEntry): string { const reportID = report?.reportID ?? '-1'; - const lastReportAction = lastVisibleReportActions[reportID] ?? null; // some types of actions are filtered out for lastReportAction, in some cases we need to check the actual last action From 3c27b60e247112532cd49471adc8dec9b2e1d933 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Tue, 31 Dec 2024 09:23:22 +0100 Subject: [PATCH 22/22] fix optional parameters --- src/libs/ReportActionsUtils.ts | 2 +- src/libs/ReportUtils.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index f659f70f552e..c89d7b52b6df 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -347,7 +347,7 @@ function isInviteOrRemovedAction( /** * Returns whether the comment is a thread parent message/the first message in a thread */ -function isThreadParentMessage(reportAction: OnyxEntry, reportID?: string): boolean { +function isThreadParentMessage(reportAction: OnyxEntry, reportID: string | undefined): boolean { const {childType, childVisibleActionCount = 0, childReportID} = reportAction ?? {}; return childType === CONST.REPORT.TYPE.CHAT && (childVisibleActionCount > 0 || String(childReportID) === reportID); } diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index c27edf3d5bcb..5596fe905d9f 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -6409,7 +6409,7 @@ function isReportNotFound(report: OnyxEntry): boolean { /** * Check if the report is the parent report of the currently viewed report or at least one child report has report action */ -function shouldHideReport(report: OnyxEntry, currentReportId?: string): boolean { +function shouldHideReport(report: OnyxEntry, currentReportId: string | undefined): boolean { const currentReport = getReportOrDraftReport(currentReportId); const parentReport = getParentReport(!isEmptyObject(currentReport) ? currentReport : undefined); const reportActions = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report?.reportID}`] ?? {}; @@ -6579,7 +6579,7 @@ function hasReportErrorsOtherThanFailedReceipt(report: Report, doesReportHaveVio type ShouldReportBeInOptionListParams = { report: OnyxEntry; - currentReportId?: string; + currentReportId: string | undefined; isInFocusMode: boolean; betas: OnyxEntry; policies: OnyxCollection;