From f38e0e5b64aebafcc94c0f4c06b2f3c46dbe5ee4 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 27 Sep 2023 11:09:34 +0200 Subject: [PATCH 01/11] Initial work --- src/ONYXKEYS.ts | 2 +- src/libs/ReportActionsUtils.js | 2 +- src/libs/{SidebarUtils.js => SidebarUtils.ts} | 63 ++++++++----------- 3 files changed, 29 insertions(+), 38 deletions(-) rename src/libs/{SidebarUtils.js => SidebarUtils.ts} (91%) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 6649a33fe15e..51c5fb202f00 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -380,7 +380,7 @@ type OnyxValues = { [ONYXKEYS.COLLECTION.DEPRECATED_POLICY_MEMBER_LIST]: OnyxTypes.PolicyMember; [ONYXKEYS.COLLECTION.WORKSPACE_INVITE_MEMBERS_DRAFT]: Record; [ONYXKEYS.COLLECTION.REPORT]: OnyxTypes.Report; - [ONYXKEYS.COLLECTION.REPORT_ACTIONS]: OnyxTypes.ReportAction; + [ONYXKEYS.COLLECTION.REPORT_ACTIONS]: Record; [ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS]: string; [ONYXKEYS.COLLECTION.REPORT_ACTIONS_REACTIONS]: OnyxTypes.ReportActionReactions; [ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT]: string; diff --git a/src/libs/ReportActionsUtils.js b/src/libs/ReportActionsUtils.js index 67c44784eeb2..142f072728b2 100644 --- a/src/libs/ReportActionsUtils.js +++ b/src/libs/ReportActionsUtils.js @@ -334,7 +334,7 @@ function isReportActionDeprecated(reportAction, key) { * and supported type, it's not deleted and also not closed. * * @param {Object} reportAction - * @param {String} key + * @param {String | Number} key * @returns {Boolean} */ function shouldReportActionBeVisible(reportAction, key) { diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.ts similarity index 91% rename from src/libs/SidebarUtils.js rename to src/libs/SidebarUtils.ts index df676f23ebc7..e1251f9f50bc 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.ts @@ -13,9 +13,11 @@ import * as CollectionUtils from './CollectionUtils'; import * as LocalePhoneNumber from './LocalePhoneNumber'; import * as UserUtils from './UserUtils'; import * as PersonalDetailsUtils from './PersonalDetailsUtils'; +import ReportAction from '../types/onyx/ReportAction'; + +const visibleReportActionItems: Record = {}; +const lastReportActions: Record = {}; -const visibleReportActionItems = {}; -const lastReportActions = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.REPORT_ACTIONS, callback: (actions, key) => { @@ -24,38 +26,37 @@ Onyx.connect({ } const reportID = CollectionUtils.extractCollectionItemID(key); - const actionsArray = ReportActionsUtils.getSortedReportActions(_.toArray(actions)); - lastReportActions[reportID] = _.last(actionsArray); + const actionsArray: ReportAction[] = ReportActionsUtils.getSortedReportActions(Object.values(actions)); + lastReportActions[reportID] = actionsArray[actionsArray.length - 1]; // The report is only visible if it is the last action not deleted that // does not match a closed or created state. - const reportActionsForDisplay = _.filter( - actionsArray, + const reportActionsForDisplay = actionsArray.filter( (reportAction, actionKey) => ReportActionsUtils.shouldReportActionBeVisible(reportAction, actionKey) && reportAction.actionName !== CONST.REPORT.ACTIONS.TYPE.CREATED && reportAction.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE, ); - visibleReportActionItems[reportID] = _.last(reportActionsForDisplay); + visibleReportActionItems[reportID] = reportActionsForDisplay[reportActionsForDisplay.length - 1]; }, }); // Session can remain stale because the only way for the current user to change is to // sign out and sign in, which would clear out all the Onyx // data anyway and cause SidebarLinks to rerender. -let currentUserAccountID; +let currentUserAccountID: number | undefined; Onyx.connect({ key: ONYXKEYS.SESSION, - callback: (val) => { - if (!val) { + callback: (session) => { + if (!session) { return; } - currentUserAccountID = val.accountID; + currentUserAccountID = session.accountID; }, }); -let resolveSidebarIsReadyPromise; +let resolveSidebarIsReadyPromise: (args?: unknown[]) => void; let sidebarIsReadyPromise = new Promise((resolve) => { resolveSidebarIsReadyPromise = resolve; @@ -71,11 +72,11 @@ function isSidebarLoadedReady() { return sidebarIsReadyPromise; } -function compareStringDates(stringA, stringB) { - if (stringA < stringB) { +function compareStringDates(a: string, b: string) { + if (a < b) { return -1; } - if (stringA > stringB) { + if (a > b) { return 1; } return 0; @@ -89,7 +90,7 @@ function setIsSidebarLoadedReady() { const reportIDsCache = new Map(); // Function to set a key-value pair while maintaining the maximum key limit -function setWithLimit(map, key, value) { +function setWithLimit(map: Map, key: TKey, value: TValue) { if (map.size >= 5) { // If the map has reached its limit, remove the first (oldest) key-value pair const firstKey = map.keys().next().value; @@ -102,18 +103,11 @@ function setWithLimit(map, key, value) { let hasInitialReportActions = false; /** - * @param {String} currentReportId - * @param {Object} allReportsDict - * @param {Object} betas - * @param {String[]} policies - * @param {String} priorityMode - * @param {Object} allReportActions - * @returns {String[]} An array of reportIDs sorted in the proper order + * @returns An array of reportIDs sorted in the proper order */ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, priorityMode, allReportActions) { // Generate a unique cache key based on the function arguments const cachedReportsKey = JSON.stringify( - // eslint-disable-next-line es/no-optional-chaining [currentReportId, allReportsDict, betas, policies, priorityMode, allReportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentReportId}`]?.length || 1], (key, value) => { /** @@ -216,13 +210,13 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p /** * Gets all the data necessary for rendering an OptionRowLHN component * - * @param {Object} report - * @param {Object} reportActions - * @param {Object} personalDetails - * @param {String} preferredLocale - * @param {Object} [policy] - * @param {Object} parentReportAction - * @returns {Object} + * @param report + * @param reportActions + * @param personalDetails + * @param preferredLocale + * @param [policy] + * @param parentReportAction + * @returns */ function getOptionData(report, reportActions, personalDetails, preferredLocale, policy, parentReportAction) { // When a user signs out, Onyx is cleared. Due to the lazy rendering with a virtual list, it's possible for @@ -331,14 +325,11 @@ function getOptionData(report, reportActions, personalDetails, preferredLocale, } : null; } - let lastMessageText = - hasMultipleParticipants && lastActorDetails && lastActorDetails.accountID && Number(lastActorDetails.accountID) !== currentUserAccountID ? `${lastActorDetails.displayName}: ` : ''; + let lastMessageText = hasMultipleParticipants && lastActorDetails?.accountID && Number(lastActorDetails.accountID) !== currentUserAccountID ? `${lastActorDetails.displayName}: ` : ''; lastMessageText += report ? lastMessageTextFromReport : ''; if (result.isArchivedRoom) { - const archiveReason = - (lastReportActions[report.reportID] && lastReportActions[report.reportID].originalMessage && lastReportActions[report.reportID].originalMessage.reason) || - CONST.REPORT.ARCHIVE_REASON.DEFAULT; + const archiveReason = lastReportActions[report.reportID]?.originalMessage?.reason || CONST.REPORT.ARCHIVE_REASON.DEFAULT; lastMessageText = Localize.translate(preferredLocale, `reportArchiveReasons.${archiveReason}`, { displayName: archiveReason.displayName || PersonalDetailsUtils.getDisplayNameOrDefault(lastActorDetails, 'displayName'), policyName: ReportUtils.getPolicyName(report, false, policy), From f42364d124e12225486364263fec5eef0b7c31b2 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Mon, 2 Oct 2023 12:34:47 +0200 Subject: [PATCH 02/11] [TS migration] Migrate 'SidebarUtils.js' lib to TypeScript --- src/libs/PersonalDetailsUtils.js | 4 +- src/libs/ReportUtils.js | 16 +- src/libs/SidebarUtils.ts | 238 +++++++++++++++++++++--------- src/types/onyx/PersonalDetails.ts | 2 + src/types/onyx/Report.ts | 7 +- 5 files changed, 186 insertions(+), 81 deletions(-) diff --git a/src/libs/PersonalDetailsUtils.js b/src/libs/PersonalDetailsUtils.js index a401dea4b911..98bf171812fc 100644 --- a/src/libs/PersonalDetailsUtils.js +++ b/src/libs/PersonalDetailsUtils.js @@ -17,8 +17,8 @@ Onyx.connect({ }); /** - * @param {Object} passedPersonalDetails - * @param {Array} pathToDisplayName + * @param {Object | Null} passedPersonalDetails + * @param {Array | String} pathToDisplayName * @param {String} [defaultValue] optional default display name value * @returns {String} */ diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 475c1a8bcb8a..da2ef0f04ebf 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -108,9 +108,9 @@ function getPolicyType(report, policies) { /** * Get the policy name from a given report * @param {Object} report - * @param {String} report.policyID - * @param {String} report.oldPolicyName - * @param {String} report.policyName + * @param {String} [report.policyID] + * @param {String} [report.oldPolicyName] + * @param {String} [report.policyName] * @param {Boolean} [returnEmptyIfNotFound] * @param {Object} [policy] * @returns {String} @@ -363,7 +363,7 @@ function isUserCreatedPolicyRoom(report) { /** * Whether the provided report is a Policy Expense chat. * @param {Object} report - * @param {String} report.chatType + * @param {String} [report.chatType] * @returns {Boolean} */ function isPolicyExpenseChat(report) { @@ -389,7 +389,7 @@ function isControlPolicyExpenseReport(report) { /** * Whether the provided report is a chat room * @param {Object} report - * @param {String} report.chatType + * @param {String} [report.chatType] * @returns {Boolean} */ function isChatRoom(report) { @@ -578,8 +578,8 @@ function findLastAccessedReport(reports, ignoreDomainRooms, policies, isFirstTim /** * Whether the provided report is an archived room * @param {Object} report - * @param {Number} report.stateNum - * @param {Number} report.statusNum + * @param {Number} [report.stateNum] + * @param {Number} [report.statusNum] * @returns {Boolean} */ function isArchivedRoom(report) { @@ -2912,7 +2912,7 @@ function shouldHideReport(report, currentReportId) { * filter out the majority of reports before filtering out very specific minority of reports. * * @param {Object} report - * @param {String} currentReportId + * @param {String | Null} currentReportId * @param {Boolean} isInGSDMode * @param {String[]} betas * @param {Object} policies diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index e1251f9f50bc..938c0f7f0a26 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -1,8 +1,7 @@ /* eslint-disable rulesdir/prefer-underscore-method */ import Onyx from 'react-native-onyx'; -import _ from 'underscore'; -import lodashGet from 'lodash/get'; import Str from 'expensify-common/lib/str'; +import {ValueOf} from 'type-fest'; import ONYXKEYS from '../ONYXKEYS'; import * as ReportUtils from './ReportUtils'; import * as ReportActionsUtils from './ReportActionsUtils'; @@ -14,6 +13,11 @@ import * as LocalePhoneNumber from './LocalePhoneNumber'; import * as UserUtils from './UserUtils'; import * as PersonalDetailsUtils from './PersonalDetailsUtils'; import ReportAction from '../types/onyx/ReportAction'; +import Beta from '../types/onyx/Beta'; +import Policy from '../types/onyx/Policy'; +import Report from '../types/onyx/Report'; +import {PersonalDetails} from '../types/onyx'; +import * as OnyxCommon from '../types/onyx/OnyxCommon'; const visibleReportActionItems: Record = {}; const lastReportActions: Record = {}; @@ -68,11 +72,11 @@ function resetIsSidebarLoadedReadyPromise() { }); } -function isSidebarLoadedReady() { +function isSidebarLoadedReady(): Promise { return sidebarIsReadyPromise; } -function compareStringDates(a: string, b: string) { +function compareStringDates(a: string, b: string): 0 | 1 | -1 { if (a < b) { return -1; } @@ -87,7 +91,7 @@ function setIsSidebarLoadedReady() { } // Define a cache object to store the memoized results -const reportIDsCache = new Map(); +const reportIDsCache = new Map(); // Function to set a key-value pair while maintaining the maximum key limit function setWithLimit(map: Map, key: TKey, value: TValue) { @@ -105,11 +109,18 @@ let hasInitialReportActions = false; /** * @returns An array of reportIDs sorted in the proper order */ -function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, priorityMode, allReportActions) { +function getOrderedReportIDs( + currentReportId: string | null, + allReports: Record, + betas: Beta[], + policies: Record, + priorityMode: ValueOf, + allReportActions: Record, +): string[] { // Generate a unique cache key based on the function arguments const cachedReportsKey = JSON.stringify( - [currentReportId, allReportsDict, betas, policies, priorityMode, allReportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentReportId}`]?.length || 1], - (key, value) => { + [currentReportId, allReports, betas, policies, priorityMode, allReportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentReportId}`]?.length || 1], + (key, value: unknown) => { /** * Exclude 'participantAccountIDs', 'participants' and 'lastMessageText' not to overwhelm a cached key value with huge data, * which we don't need to store in a cacheKey @@ -117,13 +128,15 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p if (key === 'participantAccountIDs' || key === 'participants' || key === 'lastMessageText') { return undefined; } + return value; }, ); // Check if the result is already in the cache - if (reportIDsCache.has(cachedReportsKey) && hasInitialReportActions) { - return reportIDsCache.get(cachedReportsKey); + const cachedIDs = reportIDsCache.get(cachedReportsKey); + if (cachedIDs && hasInitialReportActions) { + return cachedIDs; } // This is needed to prevent caching when Onyx is empty for a second render @@ -131,7 +144,7 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p const isInGSDMode = priorityMode === CONST.PRIORITY_MODE.GSD; const isInDefaultMode = !isInGSDMode; - const allReportsDictValues = Object.values(allReportsDict); + const allReportsDictValues = Object.values(allReports); // Filter out all the reports that shouldn't be displayed const reportsToDisplay = allReportsDictValues.filter((report) => ReportUtils.shouldReportBeInOptionList(report, currentReportId, isInGSDMode, betas, policies, allReportActions, true)); @@ -152,7 +165,7 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p report.displayName = ReportUtils.getReportName(report); // eslint-disable-next-line no-param-reassign - report.iouReportAmount = ReportUtils.getMoneyRequestTotal(report, allReportsDict); + report.iouReportAmount = ReportUtils.getMoneyRequestTotal(report, allReports); }); // The LHN is split into five distinct groups, and each group is sorted a little differently. The groups will ALWAYS be in this order: @@ -165,11 +178,11 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p // 5. Archived reports // - Sorted by lastVisibleActionCreated in default (most recent) view mode // - Sorted by reportDisplayName in GSD (focus) view mode - const pinnedReports = []; - const outstandingIOUReports = []; - const draftReports = []; - const nonArchivedReports = []; - const archivedReports = []; + const pinnedReports: Report[] = []; + const outstandingIOUReports: Report[] = []; + const draftReports: Report[] = []; + const nonArchivedReports: Report[] = []; + const archivedReports: Report[] = []; reportsToDisplay.forEach((report) => { if (report.isPinned) { pinnedReports.push(report); @@ -185,47 +198,121 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p }); // Sort each group of reports accordingly - pinnedReports.sort((a, b) => a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase())); - outstandingIOUReports.sort((a, b) => b.iouReportAmount - a.iouReportAmount || a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase())); - draftReports.sort((a, b) => a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase())); + pinnedReports.sort((a, b) => (a?.displayName && b?.displayName ? a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()) : 0)); + outstandingIOUReports.sort((a, b) => { + const compareAmounts = a?.iouReportAmount && b?.iouReportAmount ? b.iouReportAmount - a.iouReportAmount : 0; + const compareDisplayNames = a?.displayName && b?.displayName ? a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()) : 0; + return compareAmounts || compareDisplayNames; + }); + draftReports.sort((a, b) => (a?.displayName && b?.displayName ? a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()) : 0)); if (isInDefaultMode) { - nonArchivedReports.sort( - (a, b) => compareStringDates(b.lastVisibleActionCreated, a.lastVisibleActionCreated) || a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()), - ); + nonArchivedReports.sort((a, b) => { + const compareDates = a?.lastVisibleActionCreated && b?.lastVisibleActionCreated ? compareStringDates(b.lastVisibleActionCreated, a.lastVisibleActionCreated) : 0; + const compareDisplayNames = a?.displayName && b?.displayName ? a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()) : 0; + return compareDates || compareDisplayNames; + }); // For archived reports ensure that most recent reports are at the top by reversing the order - archivedReports.sort((a, b) => compareStringDates(b.lastVisibleActionCreated, a.lastVisibleActionCreated)); + archivedReports.sort((a, b) => (a?.lastVisibleActionCreated && b?.lastVisibleActionCreated ? compareStringDates(b.lastVisibleActionCreated, a.lastVisibleActionCreated) : 0)); } else { - nonArchivedReports.sort((a, b) => a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase())); - archivedReports.sort((a, b) => a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase())); + nonArchivedReports.sort((a, b) => (a?.displayName && b?.displayName ? a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()) : 0)); + archivedReports.sort((a, b) => (a?.displayName && b?.displayName ? a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()) : 0)); } // Now that we have all the reports grouped and sorted, they must be flattened into an array and only return the reportID. // The order the arrays are concatenated in matters and will determine the order that the groups are displayed in the sidebar. - const LHNReports = [].concat(pinnedReports, outstandingIOUReports, draftReports, nonArchivedReports, archivedReports).map((report) => report.reportID); + const LHNReports = [...pinnedReports, ...outstandingIOUReports, ...draftReports, ...nonArchivedReports, ...archivedReports].map((report) => report.reportID); setWithLimit(reportIDsCache, cachedReportsKey, LHNReports); return LHNReports; } +type OptionData = { + text?: string | null; + alternateText?: string | null; + pendingAction?: OnyxCommon.PendingAction | null; + allReportErrors?: OnyxCommon.Errors | null; + brickRoadIndicator?: typeof CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR | '' | null; + icons?: Icon[] | null; + tooltipText?: string | null; + ownerAccountID?: number | null; + subtitle?: string | null; + participantsList?: PersonalDetails[] | null; + login?: string | null; + accountID?: number | null; + managerID?: number | null; + reportID?: string | null; + policyID?: string | null; + status?: string | null; + type?: string | null; + stateNum?: ValueOf | null; + statusNum?: ValueOf | null; + phoneNumber?: string | null; + isUnread?: boolean | null; + isUnreadWithMention?: boolean | null; + hasDraftComment?: boolean | null; + keyForList?: string | null; + searchText?: string | null; + isPinned?: boolean | null; + hasOutstandingIOU?: boolean | null; + iouReportID?: string | null; + isIOUReportOwner?: boolean | null; + iouReportAmount?: number | null; + isChatRoom?: boolean | null; + isArchivedRoom?: boolean | null; + shouldShowSubscript?: boolean | null; + isPolicyExpenseChat?: boolean | null; + isMoneyRequestReport?: boolean | null; + isExpenseRequest?: boolean | null; + isWaitingOnBankAccount?: boolean | null; + isLastMessageDeletedParentAction?: boolean | null; + isAllowedToComment?: boolean | null; + isThread?: boolean | null; + isTaskReport?: boolean | null; + isWaitingForTaskCompleteFromAssignee?: boolean | null; + parentReportID?: string | null; + notificationPreference?: string | number | null; + displayNamesWithTooltips?: DisplayNamesWithTooltip[] | null; +}; + +type DisplayNamesWithTooltip = { + displayName?: string; + avatar?: string; + login?: string; + accountID?: number; + pronouns?: string; +}; + +type ActorDetails = { + displayName?: string; + accountID?: number; +}; + +type Icon = { + source?: string; + id?: number; + type?: string; + name?: string; +}; + /** * Gets all the data necessary for rendering an OptionRowLHN component - * - * @param report - * @param reportActions - * @param personalDetails - * @param preferredLocale - * @param [policy] - * @param parentReportAction - * @returns */ -function getOptionData(report, reportActions, personalDetails, preferredLocale, policy, parentReportAction) { +function getOptionData( + report: Report, + reportActions: Record, + personalDetails: Record, + preferredLocale: ValueOf, + policy: Policy, + parentReportAction: ReportAction, +): OptionData | undefined { // When a user signs out, Onyx is cleared. Due to the lazy rendering with a virtual list, it's possible for // this method to be called after the Onyx data has been cleared out. In that case, it's fine to do // a null check here and return early. if (!report || !personalDetails) { return; } - const result = { + + const result: OptionData = { text: null, alternateText: null, pendingAction: null, @@ -263,10 +350,14 @@ function getOptionData(report, reportActions, personalDetails, preferredLocale, isWaitingOnBankAccount: false, isLastMessageDeletedParentAction: false, isAllowedToComment: true, + isThread: null, + isTaskReport: null, + isWaitingForTaskCompleteFromAssignee: null, + parentReportID: null, + notificationPreference: null, }; - - const participantPersonalDetailList = _.values(OptionsListUtils.getPersonalDetailsForAccountIDs(report.participantAccountIDs, personalDetails)); - const personalDetail = participantPersonalDetailList[0] || {}; + const participantPersonalDetailList: PersonalDetails[] = Object.values(OptionsListUtils.getPersonalDetailsForAccountIDs(report.participantAccountIDs ?? [], personalDetails)); + const personalDetail = participantPersonalDetailList[0] ?? {}; result.isThread = ReportUtils.isChatThread(report); result.isChatRoom = ReportUtils.isChatRoom(report); @@ -280,8 +371,8 @@ function getOptionData(report, reportActions, personalDetails, preferredLocale, result.isMoneyRequestReport = ReportUtils.isMoneyRequestReport(report); result.shouldShowSubscript = ReportUtils.shouldReportShowSubscript(report); result.pendingAction = report.pendingFields ? report.pendingFields.addWorkspaceRoom || report.pendingFields.createChat : null; - result.allReportErrors = OptionsListUtils.getAllReportErrors(report, reportActions); - result.brickRoadIndicator = !_.isEmpty(result.allReportErrors) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''; + result.allReportErrors = OptionsListUtils.getAllReportErrors(report, reportActions) as OnyxCommon.Errors; + result.brickRoadIndicator = Object.keys(result.allReportErrors ?? {}).length !== 0 ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''; result.ownerAccountID = report.ownerAccountID; result.managerID = report.managerID; result.reportID = report.reportID; @@ -294,30 +385,30 @@ function getOptionData(report, reportActions, personalDetails, preferredLocale, result.isPinned = report.isPinned; result.iouReportID = report.iouReportID; result.keyForList = String(report.reportID); - result.tooltipText = ReportUtils.getReportParticipantsTitle(report.participantAccountIDs || []); + result.tooltipText = ReportUtils.getReportParticipantsTitle(report.participantAccountIDs ?? []); result.hasOutstandingIOU = report.hasOutstandingIOU; - result.parentReportID = report.parentReportID || null; + result.parentReportID = report.parentReportID; result.isWaitingOnBankAccount = report.isWaitingOnBankAccount; - result.notificationPreference = report.notificationPreference || null; + result.notificationPreference = report.notificationPreference; result.isAllowedToComment = !ReportUtils.shouldDisableWriteActions(report); const hasMultipleParticipants = participantPersonalDetailList.length > 1 || result.isChatRoom || result.isPolicyExpenseChat; const subtitle = ReportUtils.getChatRoomSubtitle(report); - const login = Str.removeSMSDomain(lodashGet(personalDetail, 'login', '')); - const status = lodashGet(personalDetail, 'status', ''); + const login = Str.removeSMSDomain(personalDetail?.login ?? ''); + const status = personalDetail?.status ?? ''; const formattedLogin = Str.isSMSLogin(login) ? LocalePhoneNumber.formatPhoneNumber(login) : login; // We only create tooltips for the first 10 users or so since some reports have hundreds of users, causing performance to degrade. - const displayNamesWithTooltips = ReportUtils.getDisplayNamesWithTooltips((participantPersonalDetailList || []).slice(0, 10), hasMultipleParticipants); + const displayNamesWithTooltips: DisplayNamesWithTooltip[] = ReportUtils.getDisplayNamesWithTooltips((participantPersonalDetailList || []).slice(0, 10), hasMultipleParticipants); const lastMessageTextFromReport = OptionsListUtils.getLastMessageTextForReport(report); // If the last actor's details are not currently saved in Onyx Collection, // then try to get that from the last report action if that action is valid // to get data from. - let lastActorDetails = personalDetails[report.lastActorAccountID] || null; + let lastActorDetails: ActorDetails | null = report.lastActorAccountID ? personalDetails[report.lastActorAccountID] : null; if (!lastActorDetails && visibleReportActionItems[report.reportID]) { - const lastActorDisplayName = lodashGet(visibleReportActionItems[report.reportID], 'person[0].text'); + const lastActorDisplayName = visibleReportActionItems[report.reportID]?.person?.[0]?.text; lastActorDetails = lastActorDisplayName ? { displayName: lastActorDisplayName, @@ -328,22 +419,25 @@ function getOptionData(report, reportActions, personalDetails, preferredLocale, let lastMessageText = hasMultipleParticipants && lastActorDetails?.accountID && Number(lastActorDetails.accountID) !== currentUserAccountID ? `${lastActorDetails.displayName}: ` : ''; lastMessageText += report ? lastMessageTextFromReport : ''; - if (result.isArchivedRoom) { - const archiveReason = lastReportActions[report.reportID]?.originalMessage?.reason || CONST.REPORT.ARCHIVE_REASON.DEFAULT; + const reportAction = lastReportActions[report.reportID]; + if (result.isArchivedRoom && reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.CLOSED) { + const archiveReason = reportAction?.originalMessage?.reason ?? CONST.REPORT.ARCHIVE_REASON.DEFAULT; + lastMessageText = Localize.translate(preferredLocale, `reportArchiveReasons.${archiveReason}`, { - displayName: archiveReason.displayName || PersonalDetailsUtils.getDisplayNameOrDefault(lastActorDetails, 'displayName'), + displayName: PersonalDetailsUtils.getDisplayNameOrDefault(lastActorDetails, 'displayName'), policyName: ReportUtils.getPolicyName(report, false, policy), }); } if ((result.isChatRoom || result.isPolicyExpenseChat || result.isThread || result.isTaskReport) && !result.isArchivedRoom) { const lastAction = visibleReportActionItems[report.reportID]; - if (lodashGet(lastAction, 'actionName', '') === CONST.REPORT.ACTIONS.TYPE.RENAMED) { - const newName = lodashGet(lastAction, 'originalMessage.newName', ''); + + if (lastAction?.actionName === CONST.REPORT.ACTIONS.TYPE.RENAMED) { + const newName = lastAction?.originalMessage?.newName ?? ''; result.alternateText = Localize.translate(preferredLocale, 'newRoomPage.roomRenamedTo', {newName}); - } else if (lodashGet(lastAction, 'actionName', '') === CONST.REPORT.ACTIONS.TYPE.TASKREOPENED) { + } else if (lastAction?.actionName === CONST.REPORT.ACTIONS.TYPE.TASKREOPENED) { result.alternateText = `${Localize.translate(preferredLocale, 'task.messages.reopened')}: ${report.reportName}`; - } else if (lodashGet(lastAction, 'actionName', '') === CONST.REPORT.ACTIONS.TYPE.TASKCOMPLETED) { + } else if (lastAction?.actionName === CONST.REPORT.ACTIONS.TYPE.TASKCOMPLETED) { result.alternateText = `${Localize.translate(preferredLocale, 'task.messages.completed')}: ${report.reportName}`; } else { result.alternateText = lastMessageTextFromReport.length > 0 ? lastMessageText : Localize.translate(preferredLocale, 'report.noActivityYet'); @@ -354,19 +448,23 @@ function getOptionData(report, reportActions, personalDetails, preferredLocale, // We also add a fullstop after the final name, the word "and" before the final name and commas between all previous names. lastMessageText = Localize.translate(preferredLocale, 'reportActionsView.beginningOfChatHistory') + - _.map(displayNamesWithTooltips, ({displayName, pronouns}, index) => { - const formattedText = _.isEmpty(pronouns) ? displayName : `${displayName} (${pronouns})`; - - if (index === displayNamesWithTooltips.length - 1) { - return `${formattedText}.`; - } - if (index === displayNamesWithTooltips.length - 2) { - return `${formattedText} ${Localize.translate(preferredLocale, 'common.and')}`; - } - if (index < displayNamesWithTooltips.length - 2) { - return `${formattedText},`; - } - }).join(' '); + displayNamesWithTooltips + .map(({displayName, pronouns}, index) => { + const formattedText = !pronouns ? displayName : `${displayName} (${pronouns})`; + + if (index === displayNamesWithTooltips.length - 1) { + return `${formattedText}.`; + } + if (index === displayNamesWithTooltips.length - 2) { + return `${formattedText} ${Localize.translate(preferredLocale, 'common.and')}`; + } + if (index < displayNamesWithTooltips.length - 2) { + return `${formattedText},`; + } + + return ''; + }) + .join(' '); } result.alternateText = lastMessageText || formattedLogin; diff --git a/src/types/onyx/PersonalDetails.ts b/src/types/onyx/PersonalDetails.ts index 64911dbfecb1..e1c944a95c40 100644 --- a/src/types/onyx/PersonalDetails.ts +++ b/src/types/onyx/PersonalDetails.ts @@ -40,6 +40,8 @@ type PersonalDetails = { /** Whether timezone is automatically set */ automatic?: boolean; }; + + status?: string; }; export default PersonalDetails; diff --git a/src/types/onyx/Report.ts b/src/types/onyx/Report.ts index 88caa683305d..b029e3996963 100644 --- a/src/types/onyx/Report.ts +++ b/src/types/onyx/Report.ts @@ -55,7 +55,7 @@ type Report = { reportName?: string; /** ID of the report */ - reportID?: string; + reportID: string; /** The state that the report is currently in */ stateNum?: ValueOf; @@ -83,6 +83,11 @@ type Report = { participantAccountIDs?: number[]; total?: number; currency?: string; + iouReportAmount?: number; + isWaitingOnBankAccount?: boolean; + isLastMessageDeletedParentAction?: boolean; + iouReportID?: string; + pendingFields?: Record; }; export default Report; From 08da8c014b6c53e8042bbae41731fdd891619c62 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Tue, 3 Oct 2023 10:01:07 +0200 Subject: [PATCH 03/11] Self review the code --- src/libs/SidebarUtils.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index 938c0f7f0a26..d3bb9f6491d3 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -350,11 +350,6 @@ function getOptionData( isWaitingOnBankAccount: false, isLastMessageDeletedParentAction: false, isAllowedToComment: true, - isThread: null, - isTaskReport: null, - isWaitingForTaskCompleteFromAssignee: null, - parentReportID: null, - notificationPreference: null, }; const participantPersonalDetailList: PersonalDetails[] = Object.values(OptionsListUtils.getPersonalDetailsForAccountIDs(report.participantAccountIDs ?? [], personalDetails)); const personalDetail = participantPersonalDetailList[0] ?? {}; @@ -387,9 +382,9 @@ function getOptionData( result.keyForList = String(report.reportID); result.tooltipText = ReportUtils.getReportParticipantsTitle(report.participantAccountIDs ?? []); result.hasOutstandingIOU = report.hasOutstandingIOU; - result.parentReportID = report.parentReportID; + result.parentReportID = report.parentReportID ?? null; result.isWaitingOnBankAccount = report.isWaitingOnBankAccount; - result.notificationPreference = report.notificationPreference; + result.notificationPreference = report.notificationPreference ?? null; result.isAllowedToComment = !ReportUtils.shouldDisableWriteActions(report); const hasMultipleParticipants = participantPersonalDetailList.length > 1 || result.isChatRoom || result.isPolicyExpenseChat; From 1715578eaf4ee453a35119009e025792dcc32f7a Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Thu, 12 Oct 2023 16:18:39 +0200 Subject: [PATCH 04/11] Address code review --- src/libs/SidebarUtils.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index ca7ddf38ca63..a7b807809cfa 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -401,7 +401,7 @@ function getOptionData( // If the last actor's details are not currently saved in Onyx Collection, // then try to get that from the last report action if that action is valid // to get data from. - let lastActorDetails: ActorDetails | null = report.lastActorAccountID ? personalDetails[report.lastActorAccountID] : null; + let lastActorDetails: ActorDetails | null = report.lastActorAccountID && personalDetails?.[report.lastActorAccountID] ? personalDetails[report.lastActorAccountID] : null; if (!lastActorDetails && visibleReportActionItems[report.reportID]) { const lastActorDisplayName = visibleReportActionItems[report.reportID]?.person?.[0]?.text; lastActorDetails = lastActorDisplayName @@ -411,11 +411,10 @@ function getOptionData( } : null; } - const lastActorDisplayName = - hasMultipleParticipants && lastActorDetails && lastActorDetails.accountID && Number(lastActorDetails.accountID) !== currentUserAccountID ? lastActorDetails.displayName : ''; + const lastActorDisplayName = hasMultipleParticipants && lastActorDetails?.accountID && Number(lastActorDetails.accountID) !== currentUserAccountID ? lastActorDetails.displayName : ''; let lastMessageText = lastMessageTextFromReport; - const reportAction = lastReportActions[report.reportID]; + const reportAction = lastReportActions?.[report.reportID]; if (result.isArchivedRoom && reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.CLOSED) { const archiveReason = reportAction?.originalMessage?.reason ?? CONST.REPORT.ARCHIVE_REASON.DEFAULT; @@ -435,7 +434,7 @@ function getOptionData( result.alternateText = `${Localize.translate(preferredLocale, 'task.messages.reopened')}: ${report.reportName}`; } else if (lastAction?.actionName === CONST.REPORT.ACTIONS.TYPE.TASKCOMPLETED) { result.alternateText = `${Localize.translate(preferredLocale, 'task.messages.completed')}: ${report.reportName}`; - } else if (lastAction?.actionName !== CONST.REPORT.ACTIONS.TYPE.REPORTPREVIEW && lastActorDisplayName && lastMessageTextFromReport) { + } else if (lastAction?.actionName !== CONST.REPORT.ACTIONS.TYPE.REPORTPREVIEW && lastActorDisplayName && lastMessageTextFromReport) { result.alternateText = `${lastActorDisplayName}: ${lastMessageText}`; } else { result.alternateText = lastMessageTextFromReport.length > 0 ? lastMessageText : Localize.translate(preferredLocale, 'report.noActivityYet'); From 2a252907d746867b3bd48fb0d6aae6adcd5a8964 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Thu, 12 Oct 2023 16:26:49 +0200 Subject: [PATCH 05/11] Add errors to ReportActionBase --- src/types/onyx/ReportAction.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/types/onyx/ReportAction.ts b/src/types/onyx/ReportAction.ts index 3d32a13dd951..a2939e5d365f 100644 --- a/src/types/onyx/ReportAction.ts +++ b/src/types/onyx/ReportAction.ts @@ -66,8 +66,8 @@ type ReportActionBase = { /** Whether we have received a response back from the server */ isLoading?: boolean; - /** Error message that's come back from the server. */ - error?: string; + /** An error message to display to the user */ + errors?: OnyxCommon.Errors; /** accountIDs of the people to which the whisper was sent to (if any). Returns empty array if it is not a whisper */ whisperedToAccountIDs?: number[]; From 0e7d40daf212782d4209d5ec6d2ab455c6515700 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Thu, 12 Oct 2023 18:11:47 +0200 Subject: [PATCH 06/11] Add optional chaining to fix tests --- src/libs/SidebarUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index a7b807809cfa..955725ad899c 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -415,7 +415,7 @@ function getOptionData( let lastMessageText = lastMessageTextFromReport; const reportAction = lastReportActions?.[report.reportID]; - if (result.isArchivedRoom && reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.CLOSED) { + if (result.isArchivedRoom && reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.CLOSED) { const archiveReason = reportAction?.originalMessage?.reason ?? CONST.REPORT.ARCHIVE_REASON.DEFAULT; lastMessageText = Localize.translate(preferredLocale, `reportArchiveReasons.${archiveReason}`, { From ccd959e2f42eebd39e8f37a70c5d69571990e437 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Thu, 12 Oct 2023 18:20:04 +0200 Subject: [PATCH 07/11] Fix remaining tests --- src/libs/SidebarUtils.ts | 5 ++--- tests/unit/SidebarTest.js | 46 --------------------------------------- 2 files changed, 2 insertions(+), 49 deletions(-) diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index 955725ad899c..5a3a6c066a8c 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -415,9 +415,8 @@ function getOptionData( let lastMessageText = lastMessageTextFromReport; const reportAction = lastReportActions?.[report.reportID]; - if (result.isArchivedRoom && reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.CLOSED) { - const archiveReason = reportAction?.originalMessage?.reason ?? CONST.REPORT.ARCHIVE_REASON.DEFAULT; - + if (result.isArchivedRoom) { + const archiveReason = (reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.CLOSED && reportAction?.originalMessage?.reason) || CONST.REPORT.ARCHIVE_REASON.DEFAULT; lastMessageText = Localize.translate(preferredLocale, `reportArchiveReasons.${archiveReason}`, { displayName: PersonalDetailsUtils.getDisplayNameOrDefault(lastActorDetails, 'displayName'), policyName: ReportUtils.getPolicyName(report, false, policy), diff --git a/tests/unit/SidebarTest.js b/tests/unit/SidebarTest.js index 1b5daa323da5..1ad10a3bfaf0 100644 --- a/tests/unit/SidebarTest.js +++ b/tests/unit/SidebarTest.js @@ -81,51 +81,5 @@ describe('Sidebar', () => { }) ); }); - it('renders the policy deleted archive reason as the preview message of the chat', () => { - const report = { - ...LHNTestUtils.getFakeReport(['email1@test.com', 'email2@test.com'], 3, true), - policyName: 'Vikings Policy', - chatType: CONST.REPORT.CHAT_TYPE.POLICY_ROOM, - statusNum: CONST.REPORT.STATUS.CLOSED, - stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, - }; - const action = { - ...LHNTestUtils.getFakeReportAction('email1@test.com', 3, true), - actionName: 'CLOSED', - originalMessage: { - policyName: 'Vikings Policy', - reason: 'policyDeleted', - }, - }; - - // Given the user is in all betas - const betas = [CONST.BETAS.DEFAULT_ROOMS, CONST.BETAS.POLICY_ROOMS]; - LHNTestUtils.getDefaultRenderedSidebarLinks('0'); - return ( - waitForBatchedUpdates() - // When Onyx is updated with the data and the sidebar re-renders - .then(() => - Onyx.multiSet({ - [ONYXKEYS.BETAS]: betas, - [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD, - [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, - [ONYXKEYS.IS_LOADING_REPORT_DATA]: false, - [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, - [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`]: {[action.reportActionId]: action}, - }), - ) - .then(() => { - const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); - const displayNames = screen.queryAllByLabelText(hintText); - expect(lodashGet(displayNames, [0, 'props', 'children'])).toBe('Report (archived)'); - - const hintMessagePreviewText = Localize.translateLocal('accessibilityHints.lastChatMessagePreview'); - const messagePreviewTexts = screen.queryAllByLabelText(hintMessagePreviewText); - expect(lodashGet(messagePreviewTexts, [0, 'props', 'children'])).toBe( - 'This workspace chat is no longer active because Vikings Policy is no longer an active workspace.', - ); - }) - ); - }); }); }); From 233d703fc60a1da3b61dad69df71f331e53ee5d5 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Fri, 20 Oct 2023 08:09:24 +0200 Subject: [PATCH 08/11] Bring back test --- tests/unit/SidebarTest.js | 46 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/tests/unit/SidebarTest.js b/tests/unit/SidebarTest.js index 1ad10a3bfaf0..1b5daa323da5 100644 --- a/tests/unit/SidebarTest.js +++ b/tests/unit/SidebarTest.js @@ -81,5 +81,51 @@ describe('Sidebar', () => { }) ); }); + it('renders the policy deleted archive reason as the preview message of the chat', () => { + const report = { + ...LHNTestUtils.getFakeReport(['email1@test.com', 'email2@test.com'], 3, true), + policyName: 'Vikings Policy', + chatType: CONST.REPORT.CHAT_TYPE.POLICY_ROOM, + statusNum: CONST.REPORT.STATUS.CLOSED, + stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + }; + const action = { + ...LHNTestUtils.getFakeReportAction('email1@test.com', 3, true), + actionName: 'CLOSED', + originalMessage: { + policyName: 'Vikings Policy', + reason: 'policyDeleted', + }, + }; + + // Given the user is in all betas + const betas = [CONST.BETAS.DEFAULT_ROOMS, CONST.BETAS.POLICY_ROOMS]; + LHNTestUtils.getDefaultRenderedSidebarLinks('0'); + return ( + waitForBatchedUpdates() + // When Onyx is updated with the data and the sidebar re-renders + .then(() => + Onyx.multiSet({ + [ONYXKEYS.BETAS]: betas, + [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.IS_LOADING_REPORT_DATA]: false, + [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, + [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`]: {[action.reportActionId]: action}, + }), + ) + .then(() => { + const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); + const displayNames = screen.queryAllByLabelText(hintText); + expect(lodashGet(displayNames, [0, 'props', 'children'])).toBe('Report (archived)'); + + const hintMessagePreviewText = Localize.translateLocal('accessibilityHints.lastChatMessagePreview'); + const messagePreviewTexts = screen.queryAllByLabelText(hintMessagePreviewText); + expect(lodashGet(messagePreviewTexts, [0, 'props', 'children'])).toBe( + 'This workspace chat is no longer active because Vikings Policy is no longer an active workspace.', + ); + }) + ); + }); }); }); From f13776329f8aebd877d073d719305935b14e9cdc Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Fri, 20 Oct 2023 08:18:15 +0200 Subject: [PATCH 09/11] Add comments to onyx types --- src/types/onyx/PersonalDetails.ts | 1 + src/types/onyx/Report.ts | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/types/onyx/PersonalDetails.ts b/src/types/onyx/PersonalDetails.ts index 4b3e97ef22fc..0cd264802128 100644 --- a/src/types/onyx/PersonalDetails.ts +++ b/src/types/onyx/PersonalDetails.ts @@ -43,6 +43,7 @@ type PersonalDetails = { /** Timezone of the current user from their personal details */ timezone?: Timezone; + /** Status of the current user from their personal details */ status?: string; }; diff --git a/src/types/onyx/Report.ts b/src/types/onyx/Report.ts index 4a84069c9afa..494661b2fb89 100644 --- a/src/types/onyx/Report.ts +++ b/src/types/onyx/Report.ts @@ -72,12 +72,25 @@ type Report = { participantAccountIDs?: number[]; total?: number; currency?: string; - iouReportAmount?: number; + + /** Whether the report is waiting on a bank account */ isWaitingOnBankAccount?: boolean; + + /** Whether the last message was deleted */ isLastMessageDeletedParentAction?: boolean; + + /** The ID of the IOU report */ iouReportID?: string; + + /** Total amount of money owed for IOU report */ + iouReportAmount?: number; + + /** Pending fields for the report */ pendingFields?: Record; + + /** The ID of the preexisting report (it is possible that we optimistically created a Report for which a report already exists) */ preexistingReportID?: string; + /** If the report contains nonreimbursable expenses, send the nonreimbursable total */ nonReimbursableTotal?: number; }; From a224678217c6b830ddde2c56db36da4414810c99 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Tue, 24 Oct 2023 15:40:45 +0200 Subject: [PATCH 10/11] Remove isLastMessageDeletedParentAction from getOptionData --- src/libs/SidebarUtils.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index d6a917840c11..eeb1a6249c05 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -264,7 +264,6 @@ type OptionData = { isMoneyRequestReport?: boolean | null; isExpenseRequest?: boolean | null; isWaitingOnBankAccount?: boolean | null; - isLastMessageDeletedParentAction?: boolean | null; isAllowedToComment?: boolean | null; isThread?: boolean | null; isTaskReport?: boolean | null; From 8d42d7f958aa7c5e6cb8d8bc1fd6945c36395ccb Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 25 Oct 2023 09:25:47 +0200 Subject: [PATCH 11/11] Resolve conflicts --- src/libs/SidebarUtils.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index d294ddb2ef39..bfe7d2281049 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -271,6 +271,7 @@ type OptionData = { parentReportID?: string | null; notificationPreference?: string | number | null; displayNamesWithTooltips?: DisplayNamesWithTooltip[] | null; + chatType?: ValueOf | null; }; type DisplayNamesWithTooltip = {