From 7a94a237f264f7479a3d87e0f58954345cc8a79c Mon Sep 17 00:00:00 2001 From: Tomasz Misiukiewicz Date: Mon, 16 Dec 2024 08:39:08 +0100 Subject: [PATCH 01/15] move pendingChatMembers to metadata --- src/libs/DebugUtils.ts | 7 -- src/libs/ReportUtils.ts | 10 +- src/libs/actions/Policy/Member.ts | 136 ++++++++++++++--------- src/libs/actions/Policy/Policy.ts | 42 ++++--- src/libs/actions/Report.ts | 31 ++++-- src/pages/ReportDetailsPage.tsx | 2 +- src/pages/ReportParticipantsPage.tsx | 3 +- src/pages/RoomMembersPage.tsx | 20 +++- src/pages/home/ReportScreen.tsx | 1 - src/types/onyx/Report.ts | 17 +-- src/types/onyx/ReportMetadata.ts | 19 ++++ src/types/utils/whitelistedReportKeys.ts | 1 - 12 files changed, 177 insertions(+), 112 deletions(-) diff --git a/src/libs/DebugUtils.ts b/src/libs/DebugUtils.ts index 9343164db1e8..d37c3ef16a1c 100644 --- a/src/libs/DebugUtils.ts +++ b/src/libs/DebugUtils.ts @@ -530,12 +530,6 @@ function validateReportDraftProperty(key: keyof Report, value: string) { }, 'number', ); - case 'pendingChatMembers': - return validateArray>(value, { - accountID: 'string', - pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION, - errors: 'object', - }); case 'fieldList': return validateObject>( value, @@ -618,7 +612,6 @@ function validateReportDraftProperty(key: keyof Report, value: string) { iouReportID: CONST.RED_BRICK_ROAD_PENDING_ACTION, preexistingReportID: CONST.RED_BRICK_ROAD_PENDING_ACTION, nonReimbursableTotal: CONST.RED_BRICK_ROAD_PENDING_ACTION, - pendingChatMembers: CONST.RED_BRICK_ROAD_PENDING_ACTION, fieldList: CONST.RED_BRICK_ROAD_PENDING_ACTION, permissions: CONST.RED_BRICK_ROAD_PENDING_ACTION, tripData: CONST.RED_BRICK_ROAD_PENDING_ACTION, diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index eb728586f8f2..7d0ee06cb5d4 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -52,8 +52,9 @@ import type {ErrorFields, Errors, Icon, PendingAction} from '@src/types/onyx/Ony import type {OriginalMessageChangeLog, PaymentMethodType} from '@src/types/onyx/OriginalMessage'; import type {Status} from '@src/types/onyx/PersonalDetails'; import type {ConnectionName} from '@src/types/onyx/Policy'; -import type {NotificationPreference, Participants, PendingChatMember, Participant as ReportParticipant} from '@src/types/onyx/Report'; +import type {NotificationPreference, Participants, Participant as ReportParticipant} from '@src/types/onyx/Report'; import type {Message, OldDotReportAction, ReportActions} from '@src/types/onyx/ReportAction'; +import type {PendingChatMember} from '@src/types/onyx/ReportMetadata'; import type {SearchPolicy, SearchReport, SearchTransaction} from '@src/types/onyx/SearchResults'; import type {Comment, TransactionChanges, WaypointCollection} from '@src/types/onyx/Transaction'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; @@ -2200,6 +2201,7 @@ function getDisplayNameForParticipant( function getParticipantsAccountIDsForDisplay(report: OnyxEntry, shouldExcludeHidden = false, shouldExcludeDeleted = false, shouldForceExcludeCurrentUser = false): number[] { const reportParticipants = report?.participants ?? {}; + const reportMetadata = getReportMetadata(report?.reportID); let participantsEntries = Object.entries(reportParticipants); // We should not show participants that have an optimistic entry with the same login in the personal details @@ -2239,7 +2241,7 @@ function getParticipantsAccountIDsForDisplay(report: OnyxEntry, shouldEx if ( shouldExcludeDeleted && - report?.pendingChatMembers?.findLast((member) => Number(member.accountID) === accountID)?.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE + reportMetadata?.pendingChatMembers?.findLast((member) => Number(member.accountID) === accountID)?.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE ) { return false; } @@ -2300,8 +2302,10 @@ function getGroupChatName(participants?: SelectedParticipant[], shouldApplyLimit return report.reportName; } + const reportMetadata = getReportMetadata(report?.reportID); + const pendingMemberAccountIDs = new Set( - report?.pendingChatMembers?.filter((member) => member.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE).map((member) => member.accountID), + reportMetadata?.pendingChatMembers?.filter((member) => member.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE).map((member) => member.accountID), ); let participantAccountIDs = participants?.map((participant) => participant.accountID) ?? diff --git a/src/libs/actions/Policy/Member.ts b/src/libs/actions/Policy/Member.ts index 3bd87683b085..8379bae73d31 100644 --- a/src/libs/actions/Policy/Member.ts +++ b/src/libs/actions/Policy/Member.ts @@ -133,6 +133,7 @@ function getPolicy(policyID: string | undefined): OnyxEntry { */ function buildAnnounceRoomMembersOnyxData(policyID: string, accountIDs: number[]): AnnounceRoomMembersOnyxData { const announceReport = ReportUtils.getRoom(CONST.REPORT.CHAT_TYPE.POLICY_ANNOUNCE, policyID); + const announceReportMetadata = ReportUtils.getReportMetadata(announceReport?.reportID); const announceRoomMembers: AnnounceRoomMembersOnyxData = { onyxOptimisticData: [], onyxFailureData: [], @@ -144,7 +145,7 @@ function buildAnnounceRoomMembersOnyxData(policyID: string, accountIDs: number[] } const participantAccountIDs = [...Object.keys(announceReport.participants ?? {}).map(Number), ...accountIDs]; - const pendingChatMembers = ReportUtils.getPendingChatMembers(accountIDs, announceReport?.pendingChatMembers ?? [], CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); + const pendingChatMembers = ReportUtils.getPendingChatMembers(accountIDs, announceReportMetadata?.pendingChatMembers ?? [], CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); announceRoomMembers.onyxOptimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, @@ -155,22 +156,30 @@ function buildAnnounceRoomMembersOnyxData(policyID: string, accountIDs: number[] }, }); - announceRoomMembers.onyxFailureData.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${announceReport?.reportID}`, - value: { - participants: accountIDs.reduce((acc, curr) => { - Object.assign(acc, {[curr]: null}); - return acc; - }, {}), - pendingChatMembers: announceReport?.pendingChatMembers ?? null, + announceRoomMembers.onyxFailureData.push( + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${announceReport?.reportID}`, + value: { + participants: accountIDs.reduce((acc, curr) => { + Object.assign(acc, {[curr]: null}); + return acc; + }, {}), + }, }, - }); + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${announceReport?.reportID}`, + value: { + pendingChatMembers: announceReportMetadata?.pendingChatMembers ?? null, + }, + }, + ); announceRoomMembers.onyxSuccessData.push({ onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${announceReport?.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${announceReport?.reportID}`, value: { - pendingChatMembers: announceReport?.pendingChatMembers ?? null, + pendingChatMembers: announceReportMetadata?.pendingChatMembers ?? null, }, }); return announceRoomMembers; @@ -214,6 +223,7 @@ function updateImportSpreadsheetData(membersLength: number): OnyxData { */ function removeOptimisticAnnounceRoomMembers(policyID: string, policyName: string, accountIDs: number[]): AnnounceRoomMembersOnyxData { const announceReport = ReportUtils.getRoom(CONST.REPORT.CHAT_TYPE.POLICY_ANNOUNCE, policyID); + const announceReportMetadata = ReportUtils.getReportMetadata(announceReport?.reportID); const announceRoomMembers: AnnounceRoomMembersOnyxData = { onyxOptimisticData: [], onyxFailureData: [], @@ -224,41 +234,57 @@ function removeOptimisticAnnounceRoomMembers(policyID: string, policyName: strin return announceRoomMembers; } - const pendingChatMembers = ReportUtils.getPendingChatMembers(accountIDs, announceReport?.pendingChatMembers ?? [], CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE); + const pendingChatMembers = ReportUtils.getPendingChatMembers(accountIDs, announceReportMetadata?.pendingChatMembers ?? [], CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE); - announceRoomMembers.onyxOptimisticData.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${announceReport.reportID}`, - value: { - pendingChatMembers, - ...(accountIDs.includes(sessionAccountID) - ? { - statusNum: CONST.REPORT.STATUS_NUM.CLOSED, - stateNum: CONST.REPORT.STATE_NUM.APPROVED, - oldPolicyName: policyName, - } - : {}), + announceRoomMembers.onyxOptimisticData.push( + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${announceReport.reportID}`, + value: { + ...(accountIDs.includes(sessionAccountID) + ? { + statusNum: CONST.REPORT.STATUS_NUM.CLOSED, + stateNum: CONST.REPORT.STATE_NUM.APPROVED, + oldPolicyName: policyName, + } + : {}), + }, }, - }); - announceRoomMembers.onyxFailureData.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${announceReport.reportID}`, - value: { - pendingChatMembers: announceReport?.pendingChatMembers ?? null, - ...(accountIDs.includes(sessionAccountID) - ? { - statusNum: announceReport.statusNum, - stateNum: announceReport.stateNum, - oldPolicyName: announceReport.oldPolicyName, - } - : {}), + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${announceReport.reportID}`, + value: { + pendingChatMembers, + }, }, - }); + ); + announceRoomMembers.onyxFailureData.push( + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${announceReport.reportID}`, + value: { + ...(accountIDs.includes(sessionAccountID) + ? { + statusNum: announceReport.statusNum, + stateNum: announceReport.stateNum, + oldPolicyName: announceReport.oldPolicyName, + } + : {}), + }, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${announceReport.reportID}`, + value: { + pendingChatMembers: announceReportMetadata?.pendingChatMembers ?? null, + }, + }, + ); announceRoomMembers.onyxSuccessData.push({ onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${announceReport.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${announceReport.reportID}`, value: { - pendingChatMembers: announceReport?.pendingChatMembers ?? null, + pendingChatMembers: announceReportMetadata?.pendingChatMembers ?? null, }, }); @@ -362,16 +388,24 @@ function removeMembers(accountIDs: number[], policyID: string) { const pendingChatMembers = ReportUtils.getPendingChatMembers(accountIDs, [], CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE); workspaceChats.forEach((report) => { - optimisticData.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${report?.reportID}`, - value: { - statusNum: CONST.REPORT.STATUS_NUM.CLOSED, - stateNum: CONST.REPORT.STATE_NUM.APPROVED, - oldPolicyName: policy?.name, - pendingChatMembers, + optimisticData.push( + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${report?.reportID}`, + value: { + statusNum: CONST.REPORT.STATUS_NUM.CLOSED, + stateNum: CONST.REPORT.STATE_NUM.APPROVED, + oldPolicyName: policy?.name, + }, }, - }); + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${report?.reportID}`, + value: { + pendingChatMembers, + }, + }, + ); successData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${report?.reportID}`, diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index f81539d1e921..f8d9728cd378 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -776,26 +776,34 @@ function leaveWorkspace(policyID: string) { return; } - optimisticData.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${report?.reportID}`, - value: { - statusNum: CONST.REPORT.STATUS_NUM.CLOSED, - stateNum: CONST.REPORT.STATE_NUM.APPROVED, - oldPolicyName: policy?.name ?? '', - pendingChatMembers, + optimisticData.push( + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${report?.reportID}`, + value: { + statusNum: CONST.REPORT.STATUS_NUM.CLOSED, + stateNum: CONST.REPORT.STATE_NUM.APPROVED, + oldPolicyName: policy?.name ?? '', + }, }, - }); + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${report?.reportID}`, + value: { + pendingChatMembers, + }, + }, + ); successData.push({ onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${report?.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${report?.reportID}`, value: { pendingChatMembers: null, }, }); failureData.push({ onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${report?.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${report?.reportID}`, value: { pendingChatMembers: null, }, @@ -989,12 +997,6 @@ function createPolicyExpenseChats(policyID: string, invitedEmailsToAccountIDs: I createChat: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, }, hasOutstandingChildRequest, - pendingChatMembers: [ - { - accountID: accountID.toString(), - pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, - }, - ], }, }, { @@ -1002,6 +1004,12 @@ function createPolicyExpenseChats(policyID: string, invitedEmailsToAccountIDs: I key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${optimisticReport.reportID}`, value: { isOptimisticReport: true, + pendingChatMembers: [ + { + accountID: accountID.toString(), + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + }, + ], }, }, ); diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 7baf66adc5c5..628562158c0c 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -3084,6 +3084,7 @@ function leaveRoom(reportID: string, isWorkspaceMemberLeavingWorkspaceRoom = fal /** Invites people to a room */ function inviteToRoom(reportID: string, inviteeEmailsToAccountIDs: InvitedEmailsToAccountIDs) { const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; + const reportMetadata = ReportUtils.getReportMetadata(reportID); if (!report) { return; } @@ -3110,7 +3111,7 @@ function inviteToRoom(reportID: string, inviteeEmailsToAccountIDs: InvitedEmails ); const newPersonalDetailsOnyxData = PersonalDetailsUtils.getPersonalDetailsOnyxDataForOptimisticUsers(newLogins, newAccountIDs); - const pendingChatMembers = ReportUtils.getPendingChatMembers(inviteeAccountIDs, report?.pendingChatMembers ?? [], CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); + const pendingChatMembers = ReportUtils.getPendingChatMembers(inviteeAccountIDs, reportMetadata?.pendingChatMembers ?? [], CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); const newParticipantAccountCleanUp = newAccountIDs.reduce>((participantCleanUp, newAccountID) => { // eslint-disable-next-line no-param-reassign @@ -3130,8 +3131,8 @@ function inviteToRoom(reportID: string, inviteeEmailsToAccountIDs: InvitedEmails ]; optimisticData.push(...newPersonalDetailsOnyxData.optimisticData); - const successPendingChatMembers = report?.pendingChatMembers - ? report?.pendingChatMembers?.filter( + const successPendingChatMembers = reportMetadata?.pendingChatMembers + ? reportMetadata?.pendingChatMembers?.filter( (pendingMember) => !(inviteeAccountIDs.includes(Number(pendingMember.accountID)) && pendingMember.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE), ) : null; @@ -3150,7 +3151,7 @@ function inviteToRoom(reportID: string, inviteeEmailsToAccountIDs: InvitedEmails const failureData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`, value: { pendingChatMembers: pendingChatMembers.map((pendingChatMember) => { @@ -3189,12 +3190,15 @@ function inviteToRoom(reportID: string, inviteeEmailsToAccountIDs: InvitedEmails function clearAddRoomMemberError(reportID: string, invitedAccountID: string) { const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; + const reportMetadata = ReportUtils.getReportMetadata(reportID); Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, { - pendingChatMembers: report?.pendingChatMembers?.filter((pendingChatMember) => pendingChatMember.accountID !== invitedAccountID), participants: { [invitedAccountID]: null, }, }); + Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`, { + pendingChatMembers: reportMetadata?.pendingChatMembers?.filter((pendingChatMember) => pendingChatMember.accountID !== invitedAccountID), + }); Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, { [invitedAccountID]: null, }); @@ -3251,6 +3255,7 @@ function inviteToGroupChat(reportID: string, inviteeEmailsToAccountIDs: InvitedE */ function removeFromRoom(reportID: string, targetAccountIDs: number[]) { const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; + const reportMetadata = ReportUtils.getReportMetadata(reportID); if (!report) { return; } @@ -3259,12 +3264,12 @@ function removeFromRoom(reportID: string, targetAccountIDs: number[]) { targetAccountIDs.forEach((accountID) => { removeParticipantsData[accountID] = null; }); - const pendingChatMembers = ReportUtils.getPendingChatMembers(targetAccountIDs, report?.pendingChatMembers ?? [], CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE); + const pendingChatMembers = ReportUtils.getPendingChatMembers(targetAccountIDs, reportMetadata?.pendingChatMembers ?? [], CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE); const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`, value: { pendingChatMembers, }, @@ -3274,9 +3279,9 @@ function removeFromRoom(reportID: string, targetAccountIDs: number[]) { const failureData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`, value: { - pendingChatMembers: report?.pendingChatMembers ?? null, + pendingChatMembers: reportMetadata?.pendingChatMembers ?? null, }, }, ]; @@ -3289,7 +3294,13 @@ function removeFromRoom(reportID: string, targetAccountIDs: number[]) { key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, value: { participants: removeParticipantsData, - pendingChatMembers: report?.pendingChatMembers ?? null, + }, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`, + value: { + pendingChatMembers: reportMetadata?.pendingChatMembers ?? null, }, }, ]; diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index 9d2d7e4ada75..f77b8dc4e286 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -163,7 +163,7 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta // Get the active chat members by filtering out the pending members with delete action const activeChatMembers = participants.flatMap((accountID) => { - const pendingMember = report?.pendingChatMembers?.findLast((member) => member.accountID === accountID.toString()); + const pendingMember = reportMetadata?.pendingChatMembers?.findLast((member) => member.accountID === accountID.toString()); const detail = personalDetails?.[accountID]; if (!detail) { return []; diff --git a/src/pages/ReportParticipantsPage.tsx b/src/pages/ReportParticipantsPage.tsx index 4c63cc4b4492..629ec4a9c828 100755 --- a/src/pages/ReportParticipantsPage.tsx +++ b/src/pages/ReportParticipantsPage.tsx @@ -58,6 +58,7 @@ function ReportParticipantsPage({report, route}: ReportParticipantsPageProps) { const textInputRef = useRef(null); const [userSearchPhrase] = useOnyx(ONYXKEYS.ROOM_MEMBERS_USER_SEARCH_PHRASE); const [reportNameValuePairs] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report?.reportID ?? -1}`); + const [reportMetadata] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${report?.reportID ?? -1}`); const {selectionMode} = useMobileSelectionMode(); const [session] = useOnyx(ONYXKEYS.SESSION); const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST); @@ -78,7 +79,7 @@ function ReportParticipantsPage({report, route}: ReportParticipantsPageProps) { const chatParticipants = ReportUtils.getParticipantsList(report, personalDetails); - const pendingChatMembers = report?.pendingChatMembers; + const pendingChatMembers = reportMetadata?.pendingChatMembers; const reportParticipants = report?.participants; // Get the active chat members by filtering out the pending members with delete action diff --git a/src/pages/RoomMembersPage.tsx b/src/pages/RoomMembersPage.tsx index 0f29f1d00ba9..df0900793cf0 100644 --- a/src/pages/RoomMembersPage.tsx +++ b/src/pages/RoomMembersPage.tsx @@ -48,6 +48,7 @@ function RoomMembersPage({report, policies}: RoomMembersPageProps) { const route = useRoute>(); const styles = useThemeStyles(); const [session] = useOnyx(ONYXKEYS.SESSION); + const [reportMetadata] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${report?.reportID}`); const currentUserAccountID = Number(session?.accountID); const {formatPhoneNumber, translate} = useLocalize(); const [selectedMembers, setSelectedMembers] = useState([]); @@ -175,7 +176,7 @@ function RoomMembersPage({report, policies}: RoomMembersPageProps) { const shouldShowTextInput = useMemo(() => { // Get the active chat members by filtering out the pending members with delete action const activeParticipants = participants.filter((accountID) => { - const pendingMember = report?.pendingChatMembers?.findLast((member) => member.accountID === accountID.toString()); + const pendingMember = reportMetadata?.pendingChatMembers?.findLast((member) => member.accountID === accountID.toString()); if (!personalDetails?.[accountID]) { return false; } @@ -183,7 +184,7 @@ function RoomMembersPage({report, policies}: RoomMembersPageProps) { return !pendingMember || isOffline || pendingMember.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE; }); return activeParticipants.length >= CONST.STANDARD_LIST_ITEM_LIMIT; - }, [participants, personalDetails, isOffline, report]); + }, [participants, reportMetadata?.pendingChatMembers, personalDetails, isOffline]); useEffect(() => { if (!isFocusedScreen || !shouldShowTextInput) { @@ -218,7 +219,7 @@ function RoomMembersPage({report, policies}: RoomMembersPageProps) { if (!details || (searchValue.trim() && !OptionsListUtils.isSearchStringMatchUserDetails(details, searchValue))) { return; } - const pendingChatMember = report?.pendingChatMembers?.findLast((member) => member.accountID === accountID.toString()); + const pendingChatMember = reportMetadata?.pendingChatMembers?.findLast((member) => member.accountID === accountID.toString()); const isAdmin = PolicyUtils.isUserPolicyAdmin(policy, details.login); const isDisabled = pendingChatMember?.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || details.isOptimisticPersonalDetail; const isDisabledCheckbox = @@ -251,7 +252,18 @@ function RoomMembersPage({report, policies}: RoomMembersPageProps) { result = result.sort((value1, value2) => localeCompare(value1.text ?? '', value2.text ?? '')); return result; - }, [formatPhoneNumber, isPolicyExpenseChat, participants, personalDetails, policy, report.ownerAccountID, report?.pendingChatMembers, searchValue, selectedMembers, session?.accountID]); + }, [ + formatPhoneNumber, + isPolicyExpenseChat, + participants, + personalDetails, + policy, + report.ownerAccountID, + reportMetadata?.pendingChatMembers, + searchValue, + selectedMembers, + session?.accountID, + ]); const dismissError = useCallback( (item: ListItem) => { diff --git a/src/pages/home/ReportScreen.tsx b/src/pages/home/ReportScreen.tsx index 47315b604f0b..798f7dec2190 100644 --- a/src/pages/home/ReportScreen.tsx +++ b/src/pages/home/ReportScreen.tsx @@ -228,7 +228,6 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro permissions, invoiceReceiver: reportOnyx.invoiceReceiver, policyAvatar: reportOnyx.policyAvatar, - pendingChatMembers: reportOnyx.pendingChatMembers, }, [reportOnyx, permissions], ); diff --git a/src/types/onyx/Report.ts b/src/types/onyx/Report.ts index b89b6c8e0777..3b62859cf139 100644 --- a/src/types/onyx/Report.ts +++ b/src/types/onyx/Report.ts @@ -23,18 +23,6 @@ type Note = OnyxCommon.OnyxValueWithOfflineFeedback<{ errors?: OnyxCommon.Errors; }>; -/** The pending member of report */ -type PendingChatMember = { - /** Account ID of the pending member */ - accountID: string; - - /** Action to be applied to the pending member of report */ - pendingAction: OnyxCommon.PendingAction; - - /** Collection of errors to show to the user */ - errors?: OnyxCommon.Errors; -}; - /** Report participant properties */ type Participant = OnyxCommon.OnyxValueWithOfflineFeedback<{ /** What is the role of the participant in the report */ @@ -211,9 +199,6 @@ type Report = OnyxCommon.OnyxValueWithOfflineFeedback< /** Collection of participant private notes, indexed by their accountID */ privateNotes?: Record; - /** Pending members of the report */ - pendingChatMembers?: PendingChatMember[]; - /** Collection of policy report fields, indexed by their fieldID */ fieldList?: Record; @@ -244,4 +229,4 @@ type ReportCollectionDataSet = CollectionDataSet Date: Mon, 16 Dec 2024 11:09:37 +0100 Subject: [PATCH 02/15] save report metadata as key value pairs --- src/libs/ReportUtils.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 7d0ee06cb5d4..7ccef3b73af7 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -703,6 +703,7 @@ Onyx.connect({ }); let allReportMetadata: OnyxCollection; +const allReportMetadataKeyValue: Record = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.REPORT_METADATA, waitForCollectionCallback: true, @@ -711,6 +712,15 @@ Onyx.connect({ return; } allReportMetadata = value; + + Object.entries(value).forEach(([reportID, reportMetadata]) => { + if (!reportMetadata) { + return; + } + + const [, id] = reportID.split('_'); + allReportMetadataKeyValue[id] = reportMetadata; + }); }, }); @@ -8511,7 +8521,7 @@ function hasInvoiceReports() { } function getReportMetadata(reportID?: string) { - return allReportMetadata?.[`${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`]; + return allReportMetadataKeyValue[reportID ?? '-1']; } export { From b53c8b19fa4f9bbbded3c8e99e93fc340a6022d8 Mon Sep 17 00:00:00 2001 From: Tomasz Misiukiewicz Date: Tue, 17 Dec 2024 09:27:07 +0100 Subject: [PATCH 03/15] add migration for pending members --- src/libs/migrateOnyx.ts | 2 + .../migrations/PendingMembersToMetadata.ts | 54 +++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 src/libs/migrations/PendingMembersToMetadata.ts diff --git a/src/libs/migrateOnyx.ts b/src/libs/migrateOnyx.ts index 7053c2f6f75f..f0a9ec9db977 100644 --- a/src/libs/migrateOnyx.ts +++ b/src/libs/migrateOnyx.ts @@ -2,6 +2,7 @@ import Log from './Log'; import KeyReportActionsDraftByReportActionID from './migrations/KeyReportActionsDraftByReportActionID'; import MoveIsOptimisticReportToMetadata from './migrations/MoveIsOptimisticReportToMetadata'; import NVPMigration from './migrations/NVPMigration'; +import PendingMembersToMetadata from './migrations/PendingMembersToMetadata'; import PronounsMigration from './migrations/PronounsMigration'; import RemoveEmptyReportActionsDrafts from './migrations/RemoveEmptyReportActionsDrafts'; import RenameCardIsVirtual from './migrations/RenameCardIsVirtual'; @@ -23,6 +24,7 @@ export default function () { NVPMigration, PronounsMigration, MoveIsOptimisticReportToMetadata, + PendingMembersToMetadata, ]; // Reduce all promises down to a single promise. All promises run in a linear fashion, waiting for the diff --git a/src/libs/migrations/PendingMembersToMetadata.ts b/src/libs/migrations/PendingMembersToMetadata.ts new file mode 100644 index 000000000000..0935efd43cea --- /dev/null +++ b/src/libs/migrations/PendingMembersToMetadata.ts @@ -0,0 +1,54 @@ +import Onyx from 'react-native-onyx'; +import type {OnyxCollection} from 'react-native-onyx'; +import Log from '@libs/Log'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type {Report} from '@src/types/onyx'; +import type {PendingChatMember} from '@src/types/onyx/ReportMetadata'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; + +type OldReport = Report & {pendingChatMembers?: PendingChatMember[]}; + +/** + * This migration moves pendingChatMembers from the report object to reportMetadata + */ +export default function (): Promise { + return new Promise((resolve) => { + const connection = Onyx.connect({ + key: ONYXKEYS.COLLECTION.REPORT, + waitForCollectionCallback: true, + callback: (reports: OnyxCollection) => { + Onyx.disconnect(connection); + if (!reports || isEmptyObject(reports)) { + Log.info('[Migrate Onyx] Skipping migration PendingMembersToMetadata because there are no reports'); + return resolve(); + } + + const promises: Array> = []; + Object.entries(reports).forEach(([reportID, report]) => { + if (report?.pendingChatMembers === undefined) { + return; + } + + promises.push( + Promise.all([ + // @ts-expect-error pendingChatMembers is not a valid property of Report anymore + // eslint-disable-next-line rulesdir/prefer-actions-set-data + Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, {pendingChatMembers: null}), + // eslint-disable-next-line rulesdir/prefer-actions-set-data + Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`, {pendingChatMembers: report.pendingChatMembers}), + ]).then(() => { + Log.info(`[Migrate Onyx] Successfully moved pendingChatMembers to reportMetadata for ${reportID}`); + }), + ); + }); + + if (promises.length === 0) { + Log.info('[Migrate Onyx] Skipping migration PendingMembersToMetadata because there are no reports with pendingChatMembers'); + return resolve(); + } + + Promise.all(promises).then(() => resolve()); + }, + }); + }); +} From 2f34725c17ae08f2990e6f3b11415a9d61850c5e Mon Sep 17 00:00:00 2001 From: Tomasz Misiukiewicz Date: Tue, 17 Dec 2024 11:42:08 +0100 Subject: [PATCH 04/15] fix creating pending members in metadata --- src/libs/ReportUtils.ts | 3 ++- src/libs/actions/Policy/Member.ts | 22 +++++++++++++------ src/libs/actions/Policy/Policy.ts | 20 +++++++++++++++-- src/libs/actions/Report.ts | 15 +++++++++++-- .../migrations/PendingMembersToMetadata.ts | 4 ++-- 5 files changed, 50 insertions(+), 14 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 7ccef3b73af7..1c2ad277f496 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -386,6 +386,7 @@ type OptimisticWorkspaceChats = { expenseChatData: OptimisticChatReport; expenseReportActionData: Record; expenseCreatedReportActionID: string; + pendingChatMembers: PendingChatMember[]; }; type OptimisticModifiedExpenseReportAction = Pick< @@ -6073,7 +6074,6 @@ function buildOptimisticWorkspaceChats(policyID: string, policyName: string, exp false, policyName, ), - pendingChatMembers, }; const adminsChatReportID = adminsChatData.reportID; const adminsCreatedAction = buildOptimisticCreatedReportAction(CONST.POLICY.OWNER_EMAIL_FAKE); @@ -6113,6 +6113,7 @@ function buildOptimisticWorkspaceChats(policyID: string, policyName: string, exp expenseChatData, expenseReportActionData, expenseCreatedReportActionID: expenseReportCreatedAction.reportActionID, + pendingChatMembers, }; } diff --git a/src/libs/actions/Policy/Member.ts b/src/libs/actions/Policy/Member.ts index 8379bae73d31..7c769c3b522b 100644 --- a/src/libs/actions/Policy/Member.ts +++ b/src/libs/actions/Policy/Member.ts @@ -147,14 +147,22 @@ function buildAnnounceRoomMembersOnyxData(policyID: string, accountIDs: number[] const participantAccountIDs = [...Object.keys(announceReport.participants ?? {}).map(Number), ...accountIDs]; const pendingChatMembers = ReportUtils.getPendingChatMembers(accountIDs, announceReportMetadata?.pendingChatMembers ?? [], CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); - announceRoomMembers.onyxOptimisticData.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${announceReport?.reportID}`, - value: { - participants: ReportUtils.buildParticipantsFromAccountIDs(participantAccountIDs), - pendingChatMembers, + announceRoomMembers.onyxOptimisticData.push( + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${announceReport?.reportID}`, + value: { + participants: ReportUtils.buildParticipantsFromAccountIDs(participantAccountIDs), + }, }, - }); + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${announceReport?.reportID}`, + value: { + pendingChatMembers, + }, + }, + ); announceRoomMembers.onyxFailureData.push( { diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index f8d9728cd378..97eab6c31c51 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -1030,7 +1030,6 @@ function createPolicyExpenseChats(policyID: string, invitedEmailsToAccountIDs: I errorFields: { createChat: null, }, - pendingChatMembers: null, participants: { [accountID]: allPersonalDetails && allPersonalDetails[accountID] ? {} : null, }, @@ -1041,6 +1040,7 @@ function createPolicyExpenseChats(policyID: string, invitedEmailsToAccountIDs: I key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${optimisticReport.reportID}`, value: { isOptimisticReport: false, + pendingChatMembers: null, }, }, ); @@ -1660,6 +1660,7 @@ function buildPolicyData(policyOwnerEmail = '', makeMeAdmin = false, policyName expenseChatData, expenseReportActionData, expenseCreatedReportActionID, + pendingChatMembers, } = ReportUtils.buildOptimisticWorkspaceChats(policyID, workspaceName, expenseReportId); const optimisticCategoriesData = buildOptimisticPolicyCategories(policyID, CONST.POLICY.DEFAULT_CATEGORIES); @@ -1721,6 +1722,13 @@ function buildPolicyData(policyOwnerEmail = '', makeMeAdmin = false, policyName ...adminsChatData, }, }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${adminsChatReportID}`, + value: { + pendingChatMembers, + }, + }, { onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${adminsChatReportID}`, @@ -1791,7 +1799,6 @@ function buildPolicyData(policyOwnerEmail = '', makeMeAdmin = false, policyName addWorkspaceRoom: null, }, pendingAction: null, - pendingChatMembers: [], }, }, { @@ -1799,6 +1806,7 @@ function buildPolicyData(policyOwnerEmail = '', makeMeAdmin = false, policyName key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${adminsChatReportID}`, value: { isOptimisticReport: false, + pendingChatMembers: [], }, }, { @@ -2240,6 +2248,7 @@ function createWorkspaceFromIOUPayment(iouReport: OnyxEntry): WorkspaceF expenseChatData: workspaceChatData, expenseReportActionData: workspaceChatReportActionData, expenseCreatedReportActionID: workspaceChatCreatedReportActionID, + pendingChatMembers, } = ReportUtils.buildOptimisticWorkspaceChats(policyID, workspaceName); if (!employeeAccountID) { @@ -2314,6 +2323,13 @@ function createWorkspaceFromIOUPayment(iouReport: OnyxEntry): WorkspaceF ...adminsChatData, }, }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${adminsChatReportID}`, + value: { + pendingChatMembers, + }, + }, { onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${adminsChatReportID}`, diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 628562158c0c..b116e59ce9d4 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -3125,6 +3125,12 @@ function inviteToRoom(reportID: string, inviteeEmailsToAccountIDs: InvitedEmails key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, value: { participants: participantsAfterInvitation, + }, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`, + value: { pendingChatMembers, }, }, @@ -3141,10 +3147,16 @@ function inviteToRoom(reportID: string, inviteeEmailsToAccountIDs: InvitedEmails onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, value: { - pendingChatMembers: successPendingChatMembers, participants: newParticipantAccountCleanUp, }, }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`, + value: { + pendingChatMembers: successPendingChatMembers, + }, + }, ]; successData.push(...newPersonalDetailsOnyxData.finallyData); @@ -3189,7 +3201,6 @@ function inviteToRoom(reportID: string, inviteeEmailsToAccountIDs: InvitedEmails } function clearAddRoomMemberError(reportID: string, invitedAccountID: string) { - const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; const reportMetadata = ReportUtils.getReportMetadata(reportID); Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, { participants: { diff --git a/src/libs/migrations/PendingMembersToMetadata.ts b/src/libs/migrations/PendingMembersToMetadata.ts index 0935efd43cea..d71dc0d17e83 100644 --- a/src/libs/migrations/PendingMembersToMetadata.ts +++ b/src/libs/migrations/PendingMembersToMetadata.ts @@ -33,9 +33,9 @@ export default function (): Promise { Promise.all([ // @ts-expect-error pendingChatMembers is not a valid property of Report anymore // eslint-disable-next-line rulesdir/prefer-actions-set-data - Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, {pendingChatMembers: null}), + Onyx.merge(reportID, {pendingChatMembers: null}), // eslint-disable-next-line rulesdir/prefer-actions-set-data - Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`, {pendingChatMembers: report.pendingChatMembers}), + Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${report.reportID}`, {pendingChatMembers: report.pendingChatMembers}), ]).then(() => { Log.info(`[Migrate Onyx] Successfully moved pendingChatMembers to reportMetadata for ${reportID}`); }), From 778451ebaead1dc008c6130d755cfd2cb2e01dc2 Mon Sep 17 00:00:00 2001 From: Tomasz Misiukiewicz Date: Wed, 18 Dec 2024 10:16:44 +0100 Subject: [PATCH 05/15] fix lint changed --- src/libs/DebugUtils.ts | 2 +- src/libs/PolicyUtils.ts | 28 ++++++++--- src/libs/ReportUtils.ts | 23 +++++++-- src/libs/actions/IOU.ts | 29 +++++++++-- src/libs/actions/Policy/Member.ts | 19 ++++--- src/libs/actions/Policy/Policy.ts | 2 +- src/libs/actions/Report.ts | 8 ++- src/pages/ReportDetailsPage.tsx | 82 +++++++++++++++++-------------- src/pages/RoomMembersPage.tsx | 6 +-- src/pages/home/ReportScreen.tsx | 42 ++++++++-------- 10 files changed, 156 insertions(+), 85 deletions(-) diff --git a/src/libs/DebugUtils.ts b/src/libs/DebugUtils.ts index d37c3ef16a1c..7862591b1766 100644 --- a/src/libs/DebugUtils.ts +++ b/src/libs/DebugUtils.ts @@ -1360,7 +1360,7 @@ function getReasonAndReportActionForRBRInLHNRow(report: Report, reportActions: O } function getTransactionID(report: OnyxEntry, reportActions: OnyxEntry) { - const transactionID = TransactionUtils.getTransactionID(report?.reportID ?? '-1'); + const transactionID = TransactionUtils.getTransactionID(report?.reportID); return Number(transactionID) > 0 ? transactionID diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 9bf68b2c5432..ea1e74df6a6c 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -197,7 +197,11 @@ function getPolicyBrickRoadIndicatorStatus(policy: OnyxEntry, isConnecti } function getPolicyRole(policy: OnyxInputOrEntry | SearchPolicy, currentUserLogin: string | undefined) { - return policy?.role ?? policy?.employeeList?.[currentUserLogin ?? '-1']?.role; + if (!policy || !currentUserLogin) { + return; + } + + return policy?.role ?? policy?.employeeList?.[currentUserLogin]?.role; } /** @@ -391,7 +395,7 @@ function isPaidGroupPolicy(policy: OnyxEntry | SearchPolicy): boolean { } function getOwnedPaidPolicies(policies: OnyxCollection | null, currentUserAccountID: number): Policy[] { - return Object.values(policies ?? {}).filter((policy): policy is Policy => isPolicyOwner(policy, currentUserAccountID ?? -1) && isPaidGroupPolicy(policy)); + return Object.values(policies ?? {}).filter((policy): policy is Policy => isPolicyOwner(policy, currentUserAccountID ?? CONST.DEFAULT_NUMBER_ID) && isPaidGroupPolicy(policy)); } function isControlPolicy(policy: OnyxEntry): boolean { @@ -400,7 +404,7 @@ function isControlPolicy(policy: OnyxEntry): boolean { function isTaxTrackingEnabled(isPolicyExpenseChat: boolean, policy: OnyxEntry, isDistanceRequest: boolean): boolean { const distanceUnit = getDistanceRateCustomUnit(policy); - const customUnitID = distanceUnit?.customUnitID ?? 0; + const customUnitID = distanceUnit?.customUnitID ?? CONST.DEFAULT_NUMBER_ID; const isPolicyTaxTrackingEnabled = isPolicyExpenseChat && policy?.tax?.trackingEnabled; const isTaxEnabledForDistance = isPolicyTaxTrackingEnabled && policy?.customUnits?.[customUnitID]?.attributes?.taxEnabled; @@ -538,7 +542,7 @@ function getDefaultApprover(policy: OnyxEntry | SearchPolicy): string { * Returns the accountID to whom the given expenseReport submits reports to in the given Policy. */ function getSubmitToAccountID(policy: OnyxEntry | SearchPolicy, expenseReport: OnyxEntry): number { - const employeeAccountID = expenseReport?.ownerAccountID ?? -1; + const employeeAccountID = expenseReport?.ownerAccountID ?? CONST.DEFAULT_NUMBER_ID; const employeeLogin = getLoginsByAccountIDs([employeeAccountID]).at(0) ?? ''; const defaultApprover = getDefaultApprover(policy); @@ -557,8 +561,8 @@ function getSubmitToAccountID(policy: OnyxEntry | SearchPolicy, expenseR return getAccountIDsByLogins([categoryAppover]).at(0) ?? -1; } - if (!tagApprover && getTagApproverRule(policy ?? '-1', tag)?.approver) { - tagApprover = getTagApproverRule(policy ?? '-1', tag)?.approver; + if (!tagApprover && getTagApproverRule(policy, tag)?.approver) { + tagApprover = getTagApproverRule(policy, tag)?.approver; } } @@ -709,7 +713,11 @@ function settingsPendingAction(settings?: string[], pendingFields?: PendingField } const key = Object.keys(pendingFields).find((setting) => settings.includes(setting)); - return pendingFields[key ?? '-1']; + + if (!key) { + return; + } + return pendingFields[key]; } function findSelectedVendorWithDefaultSelect(vendors: NetSuiteVendor[] | undefined, selectedVendorId: string | undefined) { @@ -1078,7 +1086,7 @@ function getWorkspaceAccountID(policyID: string) { if (!policy) { return 0; } - return policy.workspaceAccountID ?? 0; + return policy.workspaceAccountID ?? CONST.DEFAULT_NUMBER_ID; } function hasVBBA(policyID: string) { @@ -1087,6 +1095,10 @@ function hasVBBA(policyID: string) { } function getTagApproverRule(policyOrID: string | SearchPolicy | OnyxEntry, tagName: string) { + if (!policyOrID) { + return; + } + const policy = typeof policyOrID === 'string' ? getPolicy(policyOrID) : policyOrID; const approvalRules = policy?.rules?.approvalRules ?? []; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 7af15d38eb55..4e925ebc5b76 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -1758,7 +1758,11 @@ function isPayAtEndExpenseReport(reportID: string, transactions: Transaction[] | /** * Checks if a report is a transaction thread associated with a report that has only one transaction */ -function isOneTransactionThread(reportID: string, parentReportID: string, threadParentReportAction: OnyxEntry): boolean { +function isOneTransactionThread(reportID: string | undefined, parentReportID: string | undefined, threadParentReportAction: OnyxEntry): boolean { + if (!reportID || !parentReportID) { + return false; + } + const parentReportActions = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`] ?? ([] as ReportAction[]); const transactionThreadReportID = ReportActionsUtils.getOneTransactionThreadReportID(parentReportID, parentReportActions); return reportID === transactionThreadReportID && !ReportActionsUtils.isSentMoneyReportAction(threadParentReportAction); @@ -3015,7 +3019,11 @@ function getTitleReportField(reportFields: Record) { /** * Get the key for a report field */ -function getReportFieldKey(reportFieldId: string) { +function getReportFieldKey(reportFieldId: string | undefined) { + if (!reportFieldId) { + return ''; + } + // We don't need to add `expensify_` prefix to the title field key, because backend stored title under a unique key `text_title`, // and all the other report field keys are stored under `expensify_FIELD_ID`. if (reportFieldId === CONST.REPORT_FIELD_TITLE_FIELD_ID) { @@ -8228,7 +8236,16 @@ function createDraftWorkspaceAndNavigateToConfirmationScreen(transactionID: stri } } -function createDraftTransactionAndNavigateToParticipantSelector(transactionID: string, reportID: string, actionName: IOUAction, reportActionID: string): void { +function createDraftTransactionAndNavigateToParticipantSelector( + transactionID: string | undefined, + reportID: string | undefined, + actionName: IOUAction, + reportActionID: string | undefined, +): void { + if (!transactionID || !reportID || !reportActionID) { + return; + } + const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] ?? ({} as Transaction); const reportActions = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`] ?? ([] as ReportAction[]); diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 696853f49fd7..e5f256cd1bdd 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -5716,7 +5716,11 @@ function prepareToCleanUpMoneyRequest(transactionID: string, reportAction: OnyxT * @param isSingleTransactionView - whether we are in the transaction thread report * @returns The URL to navigate to */ -function getNavigationUrlOnMoneyRequestDelete(transactionID: string, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false): Route | undefined { +function getNavigationUrlOnMoneyRequestDelete(transactionID: string | undefined, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false): Route | undefined { + if (!transactionID) { + return undefined; + } + const {shouldDeleteTransactionThread, shouldDeleteIOUReport, iouReport} = prepareToCleanUpMoneyRequest(transactionID, reportAction); // Determine which report to navigate back to @@ -5739,7 +5743,16 @@ function getNavigationUrlOnMoneyRequestDelete(transactionID: string, reportActio * @param isSingleTransactionView - Whether we're in single transaction view * @returns The URL to navigate to */ -function getNavigationUrlAfterTrackExpenseDelete(chatReportID: string, transactionID: string, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false): Route | undefined { +function getNavigationUrlAfterTrackExpenseDelete( + chatReportID: string | undefined, + transactionID: string | undefined, + reportAction: OnyxTypes.ReportAction, + isSingleTransactionView = false, +): Route | undefined { + if (!chatReportID || !transactionID) { + return undefined; + } + const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`] ?? null; // If not a self DM, handle it as a regular money request @@ -5914,7 +5927,11 @@ function cleanUpMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repo * @param isSingleTransactionView - whether we are in the transaction thread report * @return the url to navigate back once the money request is deleted */ -function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false) { +function deleteMoneyRequest(transactionID: string | undefined, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false) { + if (!transactionID) { + return; + } + // STEP 1: Calculate and prepare the data const { shouldDeleteTransactionThread, @@ -6175,7 +6192,11 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor return urlToNavigateBack; } -function deleteTrackExpense(chatReportID: string, transactionID: string, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false) { +function deleteTrackExpense(chatReportID: string | undefined, transactionID: string | undefined, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false) { + if (!chatReportID || !transactionID) { + return; + } + const urlToNavigateBack = getNavigationUrlAfterTrackExpenseDelete(chatReportID, transactionID, reportAction, isSingleTransactionView); // STEP 1: Get all collections we're updating diff --git a/src/libs/actions/Policy/Member.ts b/src/libs/actions/Policy/Member.ts index 056c713b1a58..86470bc205b9 100644 --- a/src/libs/actions/Policy/Member.ts +++ b/src/libs/actions/Policy/Member.ts @@ -89,7 +89,7 @@ Onyx.connect({ key: ONYXKEYS.SESSION, callback: (val) => { sessionEmail = val?.email ?? ''; - sessionAccountID = val?.accountID ?? -1; + sessionAccountID = val?.accountID ?? CONST.DEFAULT_NUMBER_ID; }, }); @@ -229,15 +229,20 @@ function updateImportSpreadsheetData(membersLength: number): OnyxData { /** * Build optimistic data for removing users from the announcement room */ -function removeOptimisticAnnounceRoomMembers(policyID: string, policyName: string, accountIDs: number[]): AnnounceRoomMembersOnyxData { - const announceReport = ReportUtils.getRoom(CONST.REPORT.CHAT_TYPE.POLICY_ANNOUNCE, policyID); - const announceReportMetadata = ReportUtils.getReportMetadata(announceReport?.reportID); +function removeOptimisticAnnounceRoomMembers(policyID: string | undefined, policyName: string, accountIDs: number[]): AnnounceRoomMembersOnyxData { const announceRoomMembers: AnnounceRoomMembersOnyxData = { onyxOptimisticData: [], onyxFailureData: [], onyxSuccessData: [], }; + if (!policyID) { + return announceRoomMembers; + } + + const announceReport = ReportUtils.getRoom(CONST.REPORT.CHAT_TYPE.POLICY_ANNOUNCE, policyID); + const announceReportMetadata = ReportUtils.getReportMetadata(announceReport?.reportID); + if (!announceReport) { return announceRoomMembers; } @@ -319,7 +324,7 @@ function removeMembers(accountIDs: number[], policyID: string) { ReportUtils.buildOptimisticClosedReportAction(sessionEmail, policy?.name ?? '', CONST.REPORT.ARCHIVE_REASON.REMOVED_FROM_POLICY), ); - const announceRoomMembers = removeOptimisticAnnounceRoomMembers(policy?.id ?? '-1', policy?.name ?? '', accountIDs); + const announceRoomMembers = removeOptimisticAnnounceRoomMembers(policy?.id, policy?.name ?? '', accountIDs); const optimisticMembersState: OnyxCollectionInputValue = {}; const successMembersState: OnyxCollectionInputValue = {}; @@ -909,7 +914,7 @@ function acceptJoinRequest(reportID: string, reportAction: OnyxEntry policies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID ?? '-1'}`], [policies, report?.policyID]); + const policy = useMemo(() => policies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`], [policies, report?.policyID]); const isPolicyAdmin = useMemo(() => PolicyUtils.isPolicyAdmin(policy), [policy]); - const isPolicyEmployee = useMemo(() => PolicyUtils.isPolicyEmployee(report?.policyID ?? '-1', policies), [report?.policyID, policies]); + const isPolicyEmployee = useMemo(() => PolicyUtils.isPolicyEmployee(report?.policyID ?? '', policies), [report?.policyID, policies]); const isPolicyExpenseChat = useMemo(() => ReportUtils.isPolicyExpenseChat(report), [report]); const shouldUseFullTitle = useMemo(() => ReportUtils.shouldUseFullTitleToDisplay(report), [report]); const isChatRoom = useMemo(() => ReportUtils.isChatRoom(report), [report]); @@ -209,8 +207,8 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta const moneyRequestAction = transactionThreadReportID ? requestParentReportAction : parentReportAction; - const canModifyTask = Task.canModifyTask(report, session?.accountID ?? -1); - const canActionTask = Task.canActionTask(report, session?.accountID ?? -1); + const canModifyTask = Task.canModifyTask(report, session?.accountID ?? CONST.DEFAULT_NUMBER_ID); + const canActionTask = Task.canActionTask(report, session?.accountID ?? CONST.DEFAULT_NUMBER_ID); const shouldShowTaskDeleteButton = isTaskReport && !isCanceledTaskReport && @@ -239,7 +237,7 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta return; } - Report.getReportPrivateNote(report?.reportID ?? '-1'); + Report.getReportPrivateNote(report?.reportID); }, [report?.reportID, isOffline, isPrivateNotesFetchTriggered, isSelfDM]); const leaveChat = useCallback(() => { @@ -293,14 +291,12 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta const shouldShowMenuItem = shouldShowNotificationPref || shouldShowWriteCapability || (!!report?.visibility && report.chatType !== CONST.REPORT.CHAT_TYPE.INVOICE); const isPayer = ReportUtils.isPayer(session, moneyRequestReport); - const isSettled = ReportUtils.isSettled(moneyRequestReport?.reportID ?? '-1'); + const isSettled = ReportUtils.isSettled(moneyRequestReport?.reportID); const shouldShowCancelPaymentButton = caseID === CASES.MONEY_REPORT && isPayer && isSettled && ReportUtils.isExpenseReport(moneyRequestReport); - const [chatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${moneyRequestReport?.chatReportID ?? '-1'}`); + const [chatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${moneyRequestReport?.chatReportID}`); - const iouTransactionID = ReportActionsUtils.isMoneyRequestAction(requestParentReportAction) - ? ReportActionsUtils.getOriginalMessage(requestParentReportAction)?.IOUTransactionID ?? '' - : ''; + const iouTransactionID = ReportActionsUtils.isMoneyRequestAction(requestParentReportAction) ? ReportActionsUtils.getOriginalMessage(requestParentReportAction)?.IOUTransactionID : ''; const cancelPayment = useCallback(() => { if (!chatReport) { @@ -343,9 +339,9 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta shouldShowRightIcon: true, action: () => { if (shouldOpenRoomMembersPage) { - Navigation.navigate(ROUTES.ROOM_MEMBERS.getRoute(report?.reportID ?? '-1', backTo)); + Navigation.navigate(ROUTES.ROOM_MEMBERS.getRoute(report?.reportID, backTo)); } else { - Navigation.navigate(ROUTES.REPORT_PARTICIPANTS.getRoute(report?.reportID ?? '-1', backTo)); + Navigation.navigate(ROUTES.REPORT_PARTICIPANTS.getRoute(report?.reportID, backTo)); } }, }); @@ -357,7 +353,7 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta isAnonymousAction: false, shouldShowRightIcon: true, action: () => { - Navigation.navigate(ROUTES.ROOM_INVITE.getRoute(report?.reportID ?? '-1')); + Navigation.navigate(ROUTES.ROOM_INVITE.getRoute(report?.reportID)); }, }); } @@ -370,15 +366,15 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta isAnonymousAction: false, shouldShowRightIcon: true, action: () => { - Navigation.navigate(ROUTES.REPORT_SETTINGS.getRoute(report?.reportID ?? '-1', backTo)); + Navigation.navigate(ROUTES.REPORT_SETTINGS.getRoute(report?.reportID, backTo)); }, }); } if (isTrackExpenseReport && !isDeletedParentAction) { - const actionReportID = ReportUtils.getOriginalReportID(report.reportID, parentReportAction) ?? '0'; - const whisperAction = ReportActionsUtils.getTrackExpenseActionableWhisper(iouTransactionID, moneyRequestReport?.reportID ?? '0'); - const actionableWhisperReportActionID = whisperAction?.reportActionID ?? '0'; + const actionReportID = ReportUtils.getOriginalReportID(report.reportID, parentReportAction); + const whisperAction = ReportActionsUtils.getTrackExpenseActionableWhisper(iouTransactionID ?? '', moneyRequestReport?.reportID ?? ''); + const actionableWhisperReportActionID = whisperAction?.reportActionID; items.push({ key: CONST.REPORT_DETAILS_MENU_ITEM.SETTINGS, translationKey: 'actionableMentionTrackExpense.submit', @@ -493,7 +489,7 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta icon: Expensicons.Upload, isAnonymousAction: false, action: () => { - Navigation.navigate(ROUTES.REPORT_WITH_ID_DETAILS_EXPORT.getRoute(report?.reportID ?? '', connectedIntegration, backTo)); + Navigation.navigate(ROUTES.REPORT_WITH_ID_DETAILS_EXPORT.getRoute(report?.reportID, connectedIntegration, backTo)); }, }); } @@ -608,18 +604,18 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta isUsingDefaultAvatar={!report.avatarUrl} size={CONST.AVATAR_SIZE.XLARGE} avatarStyle={styles.avatarXLarge} - onViewPhotoPress={() => Navigation.navigate(ROUTES.REPORT_AVATAR.getRoute(report.reportID ?? '-1'))} + onViewPhotoPress={() => Navigation.navigate(ROUTES.REPORT_AVATAR.getRoute(report.reportID))} onImageRemoved={() => { // Calling this without a file will remove the avatar - Report.updateGroupChatAvatar(report.reportID ?? ''); + Report.updateGroupChatAvatar(report.reportID); }} - onImageSelected={(file) => Report.updateGroupChatAvatar(report.reportID ?? '-1', file)} + onImageSelected={(file) => Report.updateGroupChatAvatar(report.reportID, file)} editIcon={Expensicons.Camera} editIconStyle={styles.smallEditIconAccount} pendingAction={report.pendingFields?.avatar ?? undefined} errors={report.errorFields?.avatar ?? null} errorRowStyles={styles.mt6} - onErrorClose={() => Report.clearAvatarErrors(report.reportID ?? '-1')} + onErrorClose={() => Report.clearAvatarErrors(report.reportID)} shouldUseStyleUtilityForAnchorPosition style={[styles.w100, styles.mb3]} /> @@ -655,7 +651,7 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta PromotedActions.hold({ isTextHold: canHoldUnholdReportAction.canHoldRequest, reportAction: moneyRequestAction, - reportID: transactionThreadReportID ? report.reportID : moneyRequestAction?.childReportID ?? '-1', + reportID: transactionThreadReportID ? report.reportID : moneyRequestAction?.childReportID, isDelegateAccessRestricted, setIsNoDelegateAccessMenuVisible, currentSearchHash, @@ -689,7 +685,7 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta <> { - Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(report?.policyID ?? '')); + let policyID = report?.policyID; + + if (!policyID) { + policyID = ''; + } + + Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(policyID)); }} > {chatRoomSubtitleText} @@ -755,7 +757,7 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta const fields = ReportUtils.getAvailableReportFields(report, Object.values(policy?.fieldList ?? {})); return fields.find((reportField) => ReportUtils.isReportFieldOfTypeTitle(reportField)); }, [report, policy?.fieldList]); - const fieldKey = ReportUtils.getReportFieldKey(titleField?.fieldID ?? '-1'); + const fieldKey = ReportUtils.getReportFieldKey(titleField?.fieldID); const isFieldDisabled = ReportUtils.isReportFieldDisabled(report, titleField, policy); const shouldShowTitleField = caseID !== CASES.MONEY_REQUEST && !isFieldDisabled && ReportUtils.isAdminOwnerApproverOrReportOwner(report, policy); @@ -790,7 +792,15 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta titleStyle={styles.newKansasLarge} shouldCheckActionAllowedOnPress={false} description={Str.UCFirst(titleField.name)} - onPress={() => Navigation.navigate(ROUTES.EDIT_REPORT_FIELD_REQUEST.getRoute(report.reportID, report.policyID ?? '-1', titleField.fieldID ?? '-1', backTo))} + onPress={() => { + let policyID = report.policyID; + + if (!policyID) { + policyID = ''; + } + + Navigation.navigate(ROUTES.EDIT_REPORT_FIELD_REQUEST.getRoute(report.reportID, policyID, titleField.fieldID, backTo)); + }} furtherDetailsComponent={nameSectionFurtherDetailsContent} /> @@ -810,7 +820,7 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta const isTrackExpense = ReportActionsUtils.isTrackExpenseAction(requestParentReportAction); if (isTrackExpense) { - IOU.deleteTrackExpense(moneyRequestReport?.reportID ?? '', iouTransactionID, requestParentReportAction, isSingleTransactionView); + IOU.deleteTrackExpense(moneyRequestReport?.reportID, iouTransactionID, requestParentReportAction, isSingleTransactionView); } else { IOU.deleteMoneyRequest(iouTransactionID, requestParentReportAction, isSingleTransactionView); } @@ -851,7 +861,7 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta if (!isEmptyObject(requestParentReportAction)) { const isTrackExpense = ReportActionsUtils.isTrackExpenseAction(requestParentReportAction); if (isTrackExpense) { - urlToNavigateBack = IOU.getNavigationUrlAfterTrackExpenseDelete(moneyRequestReport?.reportID ?? '', iouTransactionID, requestParentReportAction, isSingleTransactionView); + urlToNavigateBack = IOU.getNavigationUrlAfterTrackExpenseDelete(moneyRequestReport?.reportID, iouTransactionID, requestParentReportAction, isSingleTransactionView); } else { urlToNavigateBack = IOU.getNavigationUrlOnMoneyRequestDelete(iouTransactionID, requestParentReportAction, isSingleTransactionView); } diff --git a/src/pages/RoomMembersPage.tsx b/src/pages/RoomMembersPage.tsx index df0900793cf0..7d578248f634 100644 --- a/src/pages/RoomMembersPage.tsx +++ b/src/pages/RoomMembersPage.tsx @@ -57,7 +57,7 @@ function RoomMembersPage({report, policies}: RoomMembersPageProps) { const [searchValue, setSearchValue] = useState(''); const [didLoadRoomMembers, setDidLoadRoomMembers] = useState(false); const personalDetails = usePersonalDetails(); - const policy = useMemo(() => policies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID ?? ''}`], [policies, report?.policyID]); + const policy = useMemo(() => policies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`], [policies, report?.policyID]); const isPolicyExpenseChat = useMemo(() => ReportUtils.isPolicyExpenseChat(report), [report]); const backTo = route.params.backTo; @@ -267,7 +267,7 @@ function RoomMembersPage({report, policies}: RoomMembersPageProps) { const dismissError = useCallback( (item: ListItem) => { - Report.clearAddRoomMemberError(report.reportID, String(item.accountID ?? '-1')); + Report.clearAddRoomMemberError(report.reportID, String(item.accountID)); }, [report.reportID], ); @@ -325,7 +325,7 @@ function RoomMembersPage({report, policies}: RoomMembersPageProps) { /** Opens the room member details page */ const openRoomMemberDetails = useCallback( (item: ListItem) => { - Navigation.navigate(ROUTES.ROOM_MEMBER_DETAILS.getRoute(report.reportID, item?.accountID ?? -1, backTo)); + Navigation.navigate(ROUTES.ROOM_MEMBER_DETAILS.getRoute(report.reportID, item?.accountID, backTo)); }, [report, backTo], ); diff --git a/src/pages/home/ReportScreen.tsx b/src/pages/home/ReportScreen.tsx index ec2cdca1cab9..9e1448e5ac50 100644 --- a/src/pages/home/ReportScreen.tsx +++ b/src/pages/home/ReportScreen.tsx @@ -73,7 +73,7 @@ const defaultReportMetadata = { function getReportID(route: ReportScreenNavigationProps['route']): string { // The report ID is used in an onyx key. If it's an empty string, onyx will return // a collection instead of an individual report. - return String(route.params?.reportID || 0); + return String(route.params?.reportID); } /** @@ -94,14 +94,14 @@ function getParentReportAction(parentReportActions: OnyxEntry getParentReportAction(parentReportActions, reportOnyx?.parentReportActionID ?? ''), + selector: (parentReportActions) => getParentReportAction(parentReportActions, reportOnyx?.parentReportActionID), }); const [isLoadingApp] = useOnyx(ONYXKEYS.IS_LOADING_APP); const [workspaceTooltip] = useOnyx(ONYXKEYS.NVP_WORKSPACE_TOOLTIP); @@ -190,7 +187,7 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro () => reportOnyx && { lastReadTime: reportOnyx.lastReadTime, - reportID: reportOnyx.reportID ?? '', + reportID: reportOnyx.reportID, policyID: reportOnyx.policyID, lastVisibleActionCreated: reportOnyx.lastVisibleActionCreated, statusNum: reportOnyx.statusNum, @@ -278,7 +275,7 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro const combinedReportActions = ReportActionsUtils.getCombinedReportActions(reportActions, transactionThreadReportID ?? null, Object.values(transactionThreadReportActions)); const lastReportAction = [...combinedReportActions, parentReportAction].find((action) => ReportUtils.canEditReportAction(action) && !ReportActionsUtils.isMoneyRequestAction(action)); const isSingleTransactionView = ReportUtils.isMoneyRequest(report) || ReportUtils.isTrackExpenseReport(report); - const policy = policies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID ?? '-1'}`]; + const policy = policies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`]; const isTopMostReportId = currentReportID === reportIDFromRoute; const didSubscribeToReportLeavingEvents = useRef(false); @@ -320,7 +317,7 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro } useEffect(() => { - if (!transactionThreadReportID || !route?.params?.reportActionID || !ReportUtils.isOneTransactionThread(linkedAction?.childReportID ?? '-1', reportID ?? '', linkedAction)) { + if (!transactionThreadReportID || !route?.params?.reportActionID || !ReportUtils.isOneTransactionThread(linkedAction?.childReportID, reportID, linkedAction)) { return; } Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(route?.params?.reportID)); @@ -501,17 +498,21 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro }, []); const chatWithAccountManager = useCallback(() => { - Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(accountManagerReportID ?? '')); + if (!accountManagerReportID) { + return; + } + + Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(accountManagerReportID)); }, [accountManagerReportID]); // Clear notifications for the current report when it's opened and re-focused const clearNotifications = useCallback(() => { // Check if this is the top-most ReportScreen since the Navigator preserves multiple at a time - if (!isTopMostReportId) { + if (!isTopMostReportId || !reportID) { return; } - clearReportNotifications(reportID ?? ''); + clearReportNotifications(reportID); }, [reportID, isTopMostReportId]); useEffect(clearNotifications, [clearNotifications]); @@ -527,7 +528,7 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro return; } - Report.unsubscribeFromLeavingRoomReportChannel(reportID ?? ''); + Report.unsubscribeFromLeavingRoomReportChannel(reportID); }; // I'm disabling the warning, as it expects to use exhaustive deps, even though we want this useEffect to run only on the first render. @@ -563,11 +564,12 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro prevIsFocused || !ReportUtils.isChatThread(report) || ReportUtils.getReportNotificationPreference(report) !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN || - isSingleTransactionView + isSingleTransactionView || + !reportID ) { return; } - Report.openReport(reportID ?? ''); + Report.openReport(reportID); // We don't want to run this useEffect every time `report` is changed // Excluding shouldUseNarrowLayout from the dependency list to prevent re-triggering on screen resize events. @@ -731,7 +733,7 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro return; } // After creating the task report then navigating to task detail we don't have any report actions and the last read time is empty so We need to update the initial last read time when opening the task report detail. - Report.readNewestAction(report?.reportID ?? ''); + Report.readNewestAction(report?.reportID); }, [report]); const mostRecentReportAction = reportActions.at(0); const isMostRecentReportIOU = mostRecentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU; @@ -766,7 +768,7 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro navigation={navigation} style={screenWrapperStyle} shouldEnableKeyboardAvoidingView={isTopMostReportId || isInNarrowPaneModal} - testID={`report-screen-${reportID ?? ''}`} + testID={`report-screen-${reportID}`} > Date: Wed, 18 Dec 2024 10:26:35 +0100 Subject: [PATCH 06/15] fix lint changed part 2 --- src/libs/ReportUtils.ts | 12 +++++++++++- src/libs/actions/Policy/Policy.ts | 22 ++++++++++++++-------- src/pages/ReportParticipantsPage.tsx | 4 ++-- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 4e925ebc5b76..09c9c87f6e10 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -5121,7 +5121,17 @@ function buildOptimisticUnapprovedReportAction(amount: number, currency: string, * Builds an optimistic MOVED report action with a randomly generated reportActionID. * This action is used when we move reports across workspaces. */ -function buildOptimisticMovedReportAction(fromPolicyID: string, toPolicyID: string, newParentReportID: string, movedReportID: string, policyName: string): ReportAction { +function buildOptimisticMovedReportAction( + fromPolicyID: string | undefined, + toPolicyID: string | undefined, + newParentReportID: string | undefined, + movedReportID: string | undefined, + policyName: string, +): ReportAction | undefined { + if (!fromPolicyID || !toPolicyID || !newParentReportID || !movedReportID) { + return; + } + const originalMessage = { fromPolicyID, toPolicyID, diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index 77f23b7e8c02..1ea6be87db2a 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -196,7 +196,7 @@ Onyx.connect({ key: ONYXKEYS.SESSION, callback: (val) => { sessionEmail = val?.email ?? ''; - sessionAccountID = val?.accountID ?? -1; + sessionAccountID = val?.accountID ?? CONST.DEFAULT_NUMBER_ID; }, }); @@ -258,8 +258,8 @@ function hasInvoicingDetails(policy: OnyxEntry): boolean { * Returns a primary invoice workspace for the user */ function getInvoicePrimaryWorkspace(currentUserLogin: string | undefined): Policy | undefined { - if (PolicyUtils.canSendInvoiceFromWorkspace(activePolicyID ?? '-1')) { - return allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${activePolicyID ?? '-1'}`]; + if (PolicyUtils.canSendInvoiceFromWorkspace(activePolicyID)) { + return allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${activePolicyID}`]; } const activeAdminWorkspaces = PolicyUtils.getActiveAdminWorkspaces(allPolicies, currentUserLogin); return activeAdminWorkspaces.find((policy) => PolicyUtils.canSendInvoiceFromWorkspace(policy.id)); @@ -2536,15 +2536,19 @@ function createWorkspaceFromIOUPayment(iouReport: OnyxEntry): WorkspaceF const parentReportActionID = iouReport.parentReportActionID; const reportPreview = iouReport?.parentReportID && parentReportActionID ? parentReport?.[parentReportActionID] : undefined; + if (!reportPreview?.reportActionID) { + return; + } + optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${oldChatReportID}`, - value: {[reportPreview?.reportActionID ?? '-1']: null}, + value: {[reportPreview?.reportActionID]: null}, }); failureData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${oldChatReportID}`, - value: {[reportPreview?.reportActionID ?? '-1']: reportPreview}, + value: {[reportPreview?.reportActionID]: reportPreview}, }); // To optimistically remove the GBR from the DM we need to update the hasOutstandingChildRequest param to false @@ -2586,12 +2590,14 @@ function createWorkspaceFromIOUPayment(iouReport: OnyxEntry): WorkspaceF failureData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${memberData.workspaceChatReportID}`, - value: {[reportPreview?.reportActionID ?? '-1']: null}, + value: {[reportPreview?.reportActionID]: null}, }); // Create the MOVED report action and add it to the DM chat which indicates to the user where the report has been moved - const movedReportAction = ReportUtils.buildOptimisticMovedReportAction(oldPersonalPolicyID ?? '-1', policyID, memberData.workspaceChatReportID, iouReportID, workspaceName); - optimisticData.push({ + const movedReportAction = ReportUtils.buildOptimisticMovedReportAction(oldPersonalPolicyID, policyID, memberData.workspaceChatReportID, iouReportID, workspaceName); + if (!movedReportAction) { + return; + optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${oldChatReportID}`, value: {[movedReportAction.reportActionID]: movedReportAction}, diff --git a/src/pages/ReportParticipantsPage.tsx b/src/pages/ReportParticipantsPage.tsx index 629ec4a9c828..e02a51b26502 100755 --- a/src/pages/ReportParticipantsPage.tsx +++ b/src/pages/ReportParticipantsPage.tsx @@ -57,8 +57,8 @@ function ReportParticipantsPage({report, route}: ReportParticipantsPageProps) { const selectionListRef = useRef(null); const textInputRef = useRef(null); const [userSearchPhrase] = useOnyx(ONYXKEYS.ROOM_MEMBERS_USER_SEARCH_PHRASE); - const [reportNameValuePairs] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report?.reportID ?? -1}`); - const [reportMetadata] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${report?.reportID ?? -1}`); + const [reportNameValuePairs] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report?.reportID}`); + const [reportMetadata] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${report?.reportID}`); const {selectionMode} = useMobileSelectionMode(); const [session] = useOnyx(ONYXKEYS.SESSION); const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST); From 6378f734312c62167e04e698d893a55c37421d44 Mon Sep 17 00:00:00 2001 From: Tomasz Misiukiewicz Date: Wed, 18 Dec 2024 10:38:14 +0100 Subject: [PATCH 07/15] fix lint changed errors part 3 --- src/libs/PolicyUtils.ts | 8 +++++++- src/libs/actions/Policy/Policy.ts | 6 ++++-- src/pages/ReportDetailsPage.tsx | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index ea1e74df6a6c..c83faad5cc8f 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -242,7 +242,13 @@ const isPolicyUser = (policy: OnyxInputOrEntry, currentUserLogin?: strin const isPolicyAuditor = (policy: OnyxInputOrEntry, currentUserLogin?: string): boolean => (policy?.role ?? (currentUserLogin && policy?.employeeList?.[currentUserLogin]?.role)) === CONST.POLICY.ROLE.AUDITOR; -const isPolicyEmployee = (policyID: string, policies: OnyxCollection): boolean => Object.values(policies ?? {}).some((policy) => policy?.id === policyID); +const isPolicyEmployee = (policyID: string | undefined, policies: OnyxCollection): boolean => { + if (!policyID) { + return false; + } + + return Object.values(policies ?? {}).some((policy) => policy?.id === policyID); +}; /** * Checks if the current user is an owner (creator) of the policy. diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index 1ea6be87db2a..683e8246c243 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -2595,9 +2595,11 @@ function createWorkspaceFromIOUPayment(iouReport: OnyxEntry): WorkspaceF // Create the MOVED report action and add it to the DM chat which indicates to the user where the report has been moved const movedReportAction = ReportUtils.buildOptimisticMovedReportAction(oldPersonalPolicyID, policyID, memberData.workspaceChatReportID, iouReportID, workspaceName); - if (!movedReportAction) { + if (!movedReportAction) { return; - optimisticData.push({ + } + + optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${oldChatReportID}`, value: {[movedReportAction.reportActionID]: movedReportAction}, diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index 9345481f69ba..1dcfed67e97a 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -116,7 +116,7 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta const [downloadErrorModalVisible, setDownloadErrorModalVisible] = useState(false); const policy = useMemo(() => policies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`], [policies, report?.policyID]); const isPolicyAdmin = useMemo(() => PolicyUtils.isPolicyAdmin(policy), [policy]); - const isPolicyEmployee = useMemo(() => PolicyUtils.isPolicyEmployee(report?.policyID ?? '', policies), [report?.policyID, policies]); + const isPolicyEmployee = useMemo(() => PolicyUtils.isPolicyEmployee(report?.policyID, policies), [report?.policyID, policies]); const isPolicyExpenseChat = useMemo(() => ReportUtils.isPolicyExpenseChat(report), [report]); const shouldUseFullTitle = useMemo(() => ReportUtils.shouldUseFullTitleToDisplay(report), [report]); const isChatRoom = useMemo(() => ReportUtils.isChatRoom(report), [report]); From bccb31bb896407fe04e9598bccf8622e10d87b07 Mon Sep 17 00:00:00 2001 From: Tomasz Misiukiewicz Date: Wed, 18 Dec 2024 10:47:55 +0100 Subject: [PATCH 08/15] fix typecheck --- src/libs/DebugUtils.ts | 2 +- src/pages/ReportDetailsPage.tsx | 10 +++++++++- src/pages/RoomMembersPage.tsx | 4 ++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/libs/DebugUtils.ts b/src/libs/DebugUtils.ts index 7862591b1766..796e74d8c726 100644 --- a/src/libs/DebugUtils.ts +++ b/src/libs/DebugUtils.ts @@ -1360,7 +1360,7 @@ function getReasonAndReportActionForRBRInLHNRow(report: Report, reportActions: O } function getTransactionID(report: OnyxEntry, reportActions: OnyxEntry) { - const transactionID = TransactionUtils.getTransactionID(report?.reportID); + const transactionID = TransactionUtils.getTransactionID(report?.reportID ?? ''); return Number(transactionID) > 0 ? transactionID diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index 1dcfed67e97a..a8e09bbe7c76 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -141,7 +141,15 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta const shouldDisableRename = useMemo(() => ReportUtils.shouldDisableRename(report), [report]); const parentNavigationSubtitleData = ReportUtils.getParentNavigationSubtitle(report); // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps -- policy is a dependency because `getChatRoomSubtitle` calls `getPolicyName` which in turn retrieves the value from the `policy` value stored in Onyx - const chatRoomSubtitle = useMemo(() => ReportUtils.getChatRoomSubtitle(report), [report, policy]); + const chatRoomSubtitle = useMemo(() => { + const subtitle = ReportUtils.getChatRoomSubtitle(report); + + if (subtitle) { + return subtitle; + } + + return ''; + }, [report, policy]); const isSystemChat = useMemo(() => ReportUtils.isSystemChat(report), [report]); const isGroupChat = useMemo(() => ReportUtils.isGroupChat(report), [report]); const isRootGroupChat = useMemo(() => ReportUtils.isRootGroupChat(report), [report]); diff --git a/src/pages/RoomMembersPage.tsx b/src/pages/RoomMembersPage.tsx index 7d578248f634..a14ada3d3f00 100644 --- a/src/pages/RoomMembersPage.tsx +++ b/src/pages/RoomMembersPage.tsx @@ -325,6 +325,10 @@ function RoomMembersPage({report, policies}: RoomMembersPageProps) { /** Opens the room member details page */ const openRoomMemberDetails = useCallback( (item: ListItem) => { + if (!item?.accountID) { + return; + } + Navigation.navigate(ROUTES.ROOM_MEMBER_DETAILS.getRoute(report.reportID, item?.accountID, backTo)); }, [report, backTo], From 446c9ec15f1eef8d310cae80e0fd1e933be0aee8 Mon Sep 17 00:00:00 2001 From: Tomasz Misiukiewicz Date: Wed, 18 Dec 2024 11:35:49 +0100 Subject: [PATCH 09/15] fix tests part 1 --- src/libs/PolicyUtils.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index c83faad5cc8f..f56bf5f92ac9 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -197,11 +197,17 @@ function getPolicyBrickRoadIndicatorStatus(policy: OnyxEntry, isConnecti } function getPolicyRole(policy: OnyxInputOrEntry | SearchPolicy, currentUserLogin: string | undefined) { - if (!policy || !currentUserLogin) { - return; + if (policy?.role) { + return policy.role; + } + + let userLogin = currentUserLogin; + + if (!userLogin) { + userLogin = ''; } - return policy?.role ?? policy?.employeeList?.[currentUserLogin]?.role; + return policy?.employeeList?.[userLogin]?.role; } /** From 348d10dbe1510ef41468f53a68fe1ed7e248572e Mon Sep 17 00:00:00 2001 From: Tomasz Misiukiewicz Date: Wed, 18 Dec 2024 11:38:00 +0100 Subject: [PATCH 10/15] fix PolicyUtils tests --- src/libs/PolicyUtils.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index f56bf5f92ac9..70bd783a3f56 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -201,13 +201,7 @@ function getPolicyRole(policy: OnyxInputOrEntry | SearchPolicy, currentU return policy.role; } - let userLogin = currentUserLogin; - - if (!userLogin) { - userLogin = ''; - } - - return policy?.employeeList?.[userLogin]?.role; + return currentUserLogin ? policy?.employeeList?.[currentUserLogin]?.role : undefined; } /** From c6c40093cdf4c6c77703996028830d1e9b691ddd Mon Sep 17 00:00:00 2001 From: Tomasz Misiukiewicz Date: Wed, 18 Dec 2024 12:22:13 +0100 Subject: [PATCH 11/15] ignore checking ReportScreen --- .eslintrc.changed.js | 2 +- src/pages/home/ReportScreen.tsx | 43 ++++++++++++++++----------------- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/.eslintrc.changed.js b/.eslintrc.changed.js index a72dd6a9250a..6194a8038e52 100644 --- a/.eslintrc.changed.js +++ b/.eslintrc.changed.js @@ -10,7 +10,7 @@ module.exports = { }, overrides: [ { - files: ['src/libs/ReportUtils.ts', 'src/libs/actions/IOU.ts', 'src/libs/actions/Report.ts', 'src/libs/actions/Task.ts'], + files: ['src/libs/ReportUtils.ts', 'src/libs/actions/IOU.ts', 'src/libs/actions/Report.ts', 'src/libs/actions/Task.ts', 'src/pages/home/ReportScreen.tsx'], rules: { 'rulesdir/no-default-id-values': 'off', }, diff --git a/src/pages/home/ReportScreen.tsx b/src/pages/home/ReportScreen.tsx index 9e1448e5ac50..97582f75b7b1 100644 --- a/src/pages/home/ReportScreen.tsx +++ b/src/pages/home/ReportScreen.tsx @@ -73,7 +73,7 @@ const defaultReportMetadata = { function getReportID(route: ReportScreenNavigationProps['route']): string { // The report ID is used in an onyx key. If it's an empty string, onyx will return // a collection instead of an individual report. - return String(route.params?.reportID); + return String(route.params?.reportID || 0); } /** @@ -94,14 +94,14 @@ function getParentReportAction(parentReportActions: OnyxEntry getParentReportAction(parentReportActions, reportOnyx?.parentReportActionID), + selector: (parentReportActions) => getParentReportAction(parentReportActions, reportOnyx?.parentReportActionID ?? ''), }); const [isLoadingApp] = useOnyx(ONYXKEYS.IS_LOADING_APP); const [workspaceTooltip] = useOnyx(ONYXKEYS.NVP_WORKSPACE_TOOLTIP); @@ -187,7 +190,7 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro () => reportOnyx && { lastReadTime: reportOnyx.lastReadTime, - reportID: reportOnyx.reportID, + reportID: reportOnyx.reportID ?? '', policyID: reportOnyx.policyID, lastVisibleActionCreated: reportOnyx.lastVisibleActionCreated, statusNum: reportOnyx.statusNum, @@ -226,6 +229,7 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro permissions, invoiceReceiver: reportOnyx.invoiceReceiver, policyAvatar: reportOnyx.policyAvatar, + pendingChatMembers: reportOnyx.pendingChatMembers, }, [reportOnyx, permissions], ); @@ -275,7 +279,7 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro const combinedReportActions = ReportActionsUtils.getCombinedReportActions(reportActions, transactionThreadReportID ?? null, Object.values(transactionThreadReportActions)); const lastReportAction = [...combinedReportActions, parentReportAction].find((action) => ReportUtils.canEditReportAction(action) && !ReportActionsUtils.isMoneyRequestAction(action)); const isSingleTransactionView = ReportUtils.isMoneyRequest(report) || ReportUtils.isTrackExpenseReport(report); - const policy = policies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`]; + const policy = policies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID ?? '-1'}`]; const isTopMostReportId = currentReportID === reportIDFromRoute; const didSubscribeToReportLeavingEvents = useRef(false); @@ -317,7 +321,7 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro } useEffect(() => { - if (!transactionThreadReportID || !route?.params?.reportActionID || !ReportUtils.isOneTransactionThread(linkedAction?.childReportID, reportID, linkedAction)) { + if (!transactionThreadReportID || !route?.params?.reportActionID || !ReportUtils.isOneTransactionThread(linkedAction?.childReportID ?? '-1', reportID ?? '', linkedAction)) { return; } Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(route?.params?.reportID)); @@ -498,21 +502,17 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro }, []); const chatWithAccountManager = useCallback(() => { - if (!accountManagerReportID) { - return; - } - - Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(accountManagerReportID)); + Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(accountManagerReportID ?? '')); }, [accountManagerReportID]); // Clear notifications for the current report when it's opened and re-focused const clearNotifications = useCallback(() => { // Check if this is the top-most ReportScreen since the Navigator preserves multiple at a time - if (!isTopMostReportId || !reportID) { + if (!isTopMostReportId) { return; } - clearReportNotifications(reportID); + clearReportNotifications(reportID ?? ''); }, [reportID, isTopMostReportId]); useEffect(clearNotifications, [clearNotifications]); @@ -528,7 +528,7 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro return; } - Report.unsubscribeFromLeavingRoomReportChannel(reportID); + Report.unsubscribeFromLeavingRoomReportChannel(reportID ?? ''); }; // I'm disabling the warning, as it expects to use exhaustive deps, even though we want this useEffect to run only on the first render. @@ -564,12 +564,11 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro prevIsFocused || !ReportUtils.isChatThread(report) || ReportUtils.getReportNotificationPreference(report) !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN || - isSingleTransactionView || - !reportID + isSingleTransactionView ) { return; } - Report.openReport(reportID); + Report.openReport(reportID ?? ''); // We don't want to run this useEffect every time `report` is changed // Excluding shouldUseNarrowLayout from the dependency list to prevent re-triggering on screen resize events. @@ -733,7 +732,7 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro return; } // After creating the task report then navigating to task detail we don't have any report actions and the last read time is empty so We need to update the initial last read time when opening the task report detail. - Report.readNewestAction(report?.reportID); + Report.readNewestAction(report?.reportID ?? ''); }, [report]); const mostRecentReportAction = reportActions.at(0); const isMostRecentReportIOU = mostRecentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU; @@ -768,7 +767,7 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro navigation={navigation} style={screenWrapperStyle} shouldEnableKeyboardAvoidingView={isTopMostReportId || isInNarrowPaneModal} - testID={`report-screen-${reportID}`} + testID={`report-screen-${reportID ?? ''}`} > Date: Wed, 18 Dec 2024 12:42:44 +0100 Subject: [PATCH 12/15] fix ts --- src/pages/home/ReportScreen.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/home/ReportScreen.tsx b/src/pages/home/ReportScreen.tsx index 97582f75b7b1..ec2cdca1cab9 100644 --- a/src/pages/home/ReportScreen.tsx +++ b/src/pages/home/ReportScreen.tsx @@ -229,7 +229,6 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro permissions, invoiceReceiver: reportOnyx.invoiceReceiver, policyAvatar: reportOnyx.policyAvatar, - pendingChatMembers: reportOnyx.pendingChatMembers, }, [reportOnyx, permissions], ); From d87bd22d7e66f05b247a16146ccc3fae435dc599 Mon Sep 17 00:00:00 2001 From: Tomasz Misiukiewicz Date: Thu, 19 Dec 2024 14:46:09 +0100 Subject: [PATCH 13/15] update report utils --- src/libs/ReportUtils.ts | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 168acd198be3..82b46108f944 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -5135,17 +5135,7 @@ function buildOptimisticUnapprovedReportAction(amount: number, currency: string, * Builds an optimistic MOVED report action with a randomly generated reportActionID. * This action is used when we move reports across workspaces. */ -function buildOptimisticMovedReportAction( - fromPolicyID: string | undefined, - toPolicyID: string | undefined, - newParentReportID: string | undefined, - movedReportID: string | undefined, - policyName: string, -): ReportAction | undefined { - if (!fromPolicyID || !toPolicyID || !newParentReportID || !movedReportID) { - return; - } - +function buildOptimisticMovedReportAction(fromPolicyID: string, toPolicyID: string, newParentReportID: string, movedReportID: string, policyName: string): ReportAction { const originalMessage = { fromPolicyID, toPolicyID, From b032b30ccdf9c2c0443509ad127b59972c75d273 Mon Sep 17 00:00:00 2001 From: Tomasz Misiukiewicz Date: Fri, 20 Dec 2024 09:41:43 +0100 Subject: [PATCH 14/15] update pendingChatMembers in policy members --- src/libs/actions/Policy/Member.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/Policy/Member.ts b/src/libs/actions/Policy/Member.ts index 86470bc205b9..e75e1cde99d2 100644 --- a/src/libs/actions/Policy/Member.ts +++ b/src/libs/actions/Policy/Member.ts @@ -431,14 +431,14 @@ function removeMembers(accountIDs: number[], policyID: string) { ); successData.push({ onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${report?.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${report?.reportID}`, value: { pendingChatMembers: null, }, }); failureData.push({ onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${report?.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${report?.reportID}`, value: { pendingChatMembers: null, }, From 1adec5a9e17395af2f9574b208a23a9b5329d8ad Mon Sep 17 00:00:00 2001 From: Tomasz Misiukiewicz Date: Fri, 20 Dec 2024 10:21:02 +0100 Subject: [PATCH 15/15] fix linter --- src/libs/DebugUtils.ts | 2 +- src/libs/ReportActionsUtils.ts | 12 ++++++++++-- src/libs/TransactionUtils/index.ts | 6 +++++- src/pages/ReportDetailsPage.tsx | 6 +++--- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/libs/DebugUtils.ts b/src/libs/DebugUtils.ts index 64c0a28ed121..6d360065f92d 100644 --- a/src/libs/DebugUtils.ts +++ b/src/libs/DebugUtils.ts @@ -1362,7 +1362,7 @@ function getReasonAndReportActionForRBRInLHNRow(report: Report, reportActions: O } function getTransactionID(report: OnyxEntry, reportActions: OnyxEntry) { - const transactionID = TransactionUtils.getTransactionID(report?.reportID ?? ''); + const transactionID = TransactionUtils.getTransactionID(report?.reportID); return Number(transactionID) > 0 ? transactionID diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index dd17adbda338..420031a65301 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -929,7 +929,11 @@ function getLinkedTransactionID(reportActionOrID: string | OnyxEntry isActionableTrackExpense(action) && getOriginalMessage(action)?.transactionID === transactionID); } diff --git a/src/libs/TransactionUtils/index.ts b/src/libs/TransactionUtils/index.ts index 6643cd721d45..d743ea76252d 100644 --- a/src/libs/TransactionUtils/index.ts +++ b/src/libs/TransactionUtils/index.ts @@ -1210,7 +1210,11 @@ function compareDuplicateTransactionFields( return {keep, change}; } -function getTransactionID(threadReportID: string): string | undefined { +function getTransactionID(threadReportID: string | undefined): string | undefined { + if (!threadReportID) { + return undefined; + } + const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${threadReportID}`]; const parentReportAction = ReportUtils.isThread(report) ? ReportActionsUtils.getReportAction(report.parentReportID, report.parentReportActionID) : undefined; const IOUTransactionID = ReportActionsUtils.isMoneyRequestAction(parentReportAction) ? ReportActionsUtils.getOriginalMessage(parentReportAction)?.IOUTransactionID : undefined; diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index 09b0793840bd..15de7a6e5f4a 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -131,7 +131,7 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta const isTaskReport = useMemo(() => ReportUtils.isTaskReport(report), [report]); const isSelfDM = useMemo(() => ReportUtils.isSelfDM(report), [report]); const isTrackExpenseReport = ReportUtils.isTrackExpenseReport(report); - const parentReportAction = ReportActionsUtils.getReportAction(report?.parentReportID ?? '', report?.parentReportActionID ?? ''); + const parentReportAction = ReportActionsUtils.getReportAction(report?.parentReportID, report?.parentReportActionID); const isCanceledTaskReport = ReportUtils.isCanceledTaskReport(report, parentReportAction); const canEditReportDescription = useMemo(() => ReportUtils.canEditReportDescription(report, policy), [report, policy]); const shouldShowReportDescription = isChatRoom && (canEditReportDescription || report.description !== ''); @@ -149,7 +149,7 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta } return ''; - }, [report, policy]); + }, [report]); const isSystemChat = useMemo(() => ReportUtils.isSystemChat(report), [report]); const isGroupChat = useMemo(() => ReportUtils.isGroupChat(report), [report]); const isRootGroupChat = useMemo(() => ReportUtils.isRootGroupChat(report), [report]); @@ -381,7 +381,7 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta if (isTrackExpenseReport && !isDeletedParentAction) { const actionReportID = ReportUtils.getOriginalReportID(report.reportID, parentReportAction); - const whisperAction = ReportActionsUtils.getTrackExpenseActionableWhisper(iouTransactionID ?? '', moneyRequestReport?.reportID ?? ''); + const whisperAction = ReportActionsUtils.getTrackExpenseActionableWhisper(iouTransactionID, moneyRequestReport?.reportID); const actionableWhisperReportActionID = whisperAction?.reportActionID; items.push({ key: CONST.REPORT_DETAILS_MENU_ITEM.SETTINGS,