diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index d5b95e8e0485..4517ddea1af7 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -755,7 +755,7 @@ function createOption( result.isWaitingOnBankAccount = report.isWaitingOnBankAccount; result.policyID = report.policyID; result.isSelfDM = ReportUtils.isSelfDM(report); - result.notificationPreference = report.notificationPreference; + result.notificationPreference = ReportUtils.getReportNotificationPreference(report); const visibleParticipantAccountIDs = ReportUtils.getParticipantsAccountIDsForDisplay(report, true); @@ -849,7 +849,7 @@ function getPolicyExpenseReportOption(participant: Participant | ReportUtils.Opt const expenseReport = ReportUtils.isPolicyExpenseChat(participant) ? ReportUtils.getReportOrDraftReport(participant.reportID) : null; const visibleParticipantAccountIDs = Object.entries(expenseReport?.participants ?? {}) - .filter(([, reportParticipant]) => reportParticipant && !reportParticipant.hidden) + .filter(([, reportParticipant]) => reportParticipant && reportParticipant.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN) .map(([accountID]) => Number(accountID)); const option = createOption( @@ -2500,7 +2500,7 @@ function getEmptyOptions(): Options { } function shouldUseBoldText(report: ReportUtils.OptionData): boolean { - return report.isUnread === true && report.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.MUTE; + return report.isUnread === true && ReportUtils.getReportNotificationPreference(report) !== CONST.REPORT.NOTIFICATION_PREFERENCE.MUTE; } export { diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 5a30ba661619..bdc536ac2ad3 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -154,10 +154,10 @@ type OptimisticExpenseReport = Pick< | 'statusNum' | 'total' | 'nonReimbursableTotal' - | 'notificationPreference' | 'parentReportID' | 'lastVisibleActionCreated' | 'parentReportActionID' + | 'participants' | 'fieldList' >; @@ -274,7 +274,6 @@ type OptimisticChatReport = Pick< | 'lastMessageText' | 'lastReadTime' | 'lastVisibleActionCreated' - | 'notificationPreference' | 'oldPolicyName' | 'ownerAccountID' | 'pendingFields' @@ -355,7 +354,6 @@ type OptimisticTaskReport = Pick< | 'policyID' | 'stateNum' | 'statusNum' - | 'notificationPreference' | 'parentReportActionID' | 'lastVisibleActionCreated' | 'hasParentAccess' @@ -395,7 +393,6 @@ type OptimisticIOUReport = Pick< | 'statusNum' | 'total' | 'reportName' - | 'notificationPreference' | 'parentReportID' | 'lastVisibleActionCreated' | 'fieldList' @@ -1147,6 +1144,32 @@ function isSystemChat(report: OnyxEntry): boolean { return getChatType(report) === CONST.REPORT.CHAT_TYPE.SYSTEM; } +function getDefaultNotificationPreferenceForReport(report: OnyxEntry): ValueOf { + if (isAnnounceRoom(report)) { + return CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS; + } + if (isPublicRoom(report)) { + return CONST.REPORT.NOTIFICATION_PREFERENCE.DAILY; + } + if (!getChatType(report) || isGroupChat(report)) { + return CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS; + } + if (isAdminRoom(report) || isPolicyExpenseChat(report) || isInvoiceRoom(report)) { + return CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS; + } + if (isSelfDM(report)) { + return CONST.REPORT.NOTIFICATION_PREFERENCE.MUTE; + } + return CONST.REPORT.NOTIFICATION_PREFERENCE.DAILY; +} + +/** + * Get the notification preference given a report + */ +function getReportNotificationPreference(report: OnyxEntry): ValueOf { + return report?.participants?.[currentUserAccountID ?? -1]?.notificationPreference ?? getDefaultNotificationPreferenceForReport(report); +} + const CONCIERGE_ACCOUNT_ID_STRING = CONST.ACCOUNT_ID.CONCIERGE.toString(); /** * Only returns true if this is our main 1:1 DM report with Concierge. @@ -1252,7 +1275,7 @@ function hasExpensifyGuidesEmails(accountIDs: number[]): boolean { function getMostRecentlyVisitedReport(reports: Array>, reportMetadata: OnyxCollection): OnyxEntry { const filteredReports = reports.filter((report) => { - const shouldKeep = !isChatThread(report) || report?.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; + const shouldKeep = !isChatThread(report) || getReportNotificationPreference(report) !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; return shouldKeep && !!report?.reportID && !!(reportMetadata?.[`${ONYXKEYS.COLLECTION.REPORT_METADATA}${report.reportID}`]?.lastVisitTime ?? report?.lastReadTime); }); return lodashMaxBy(filteredReports, (a) => new Date(reportMetadata?.[`${ONYXKEYS.COLLECTION.REPORT_METADATA}${a?.reportID}`]?.lastVisitTime ?? a?.lastReadTime ?? '').valueOf()); @@ -1622,13 +1645,6 @@ function isPayer(session: OnyxEntry, iouReport: OnyxEntry) { return isAdmin || (isMoneyRequestReport(iouReport) && isManager); } -/** - * Get the notification preference given a report - */ -function getReportNotificationPreference(report: OnyxEntry): string | number { - return report?.notificationPreference ?? ''; -} - /** * Checks if the current user is the action's author */ @@ -2063,7 +2079,7 @@ function getParticipantsAccountIDsForDisplay(report: OnyxEntry, shouldEx return false; } - if (shouldExcludeHidden && reportParticipants[accountID]?.hidden) { + if (shouldExcludeHidden && reportParticipants[accountID]?.notificationPreference === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN) { return false; } @@ -2116,7 +2132,7 @@ function buildParticipantsFromAccountIDs(accountIDs: number[]): Participants { const finalParticipants: Participants = {}; return accountIDs.reduce((participants, accountID) => { // eslint-disable-next-line no-param-reassign - participants[accountID] = {hidden: false}; + participants[accountID] = {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}; return participants; }, finalParticipants); } @@ -4254,8 +4270,8 @@ function buildOptimisticIOUReport(payeeAccountID: number, payerAccountID: number const policy = getPolicy(policyID); const participants: Participants = { - [payeeAccountID]: {hidden: true}, - [payerAccountID]: {hidden: true}, + [payeeAccountID]: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN}, + [payerAccountID]: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN}, }; return { @@ -4273,7 +4289,6 @@ function buildOptimisticIOUReport(payeeAccountID: number, payerAccountID: number // We don't translate reportName because the server response is always in English reportName: `${payerEmail} owes ${formattedTotal}`, - notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, parentReportID: chatReportID, lastVisibleActionCreated: DateUtils.getDBTime(), fieldList: policy?.fieldList, @@ -4328,7 +4343,11 @@ function buildOptimisticInvoiceReport(chatReportID: string, policyID: string, re stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, statusNum: CONST.REPORT.STATUS_NUM.OPEN, total, - notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, + participants: { + [currentUserAccountID ?? -1]: { + notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, + }, + }, parentReportID: chatReportID, lastVisibleActionCreated: DateUtils.getDBTime(), }; @@ -4378,7 +4397,11 @@ function buildOptimisticExpenseReport( statusNum, total: storedTotal, nonReimbursableTotal: reimbursable ? 0 : storedTotal, - notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, + participants: { + [payeeAccountID]: { + notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, + }, + }, parentReportID: chatReportID, lastVisibleActionCreated: DateUtils.getDBTime(), parentReportActionID, @@ -5038,12 +5061,11 @@ function buildOptimisticChatReport( description = '', avatarUrl = '', optimisticReportID = '', - shouldShowParticipants = true, ): OptimisticChatReport { const isWorkspaceChatType = chatType && isWorkspaceChat(chatType); const participants = participantList.reduce((reportParticipants: Participants, accountID: number) => { const participant: ReportParticipant = { - hidden: !shouldShowParticipants, + notificationPreference, ...(!isWorkspaceChatType && {role: accountID === currentUserAccountID ? CONST.REPORT.ROLE.ADMIN : CONST.REPORT.ROLE.MEMBER}), }; // eslint-disable-next-line no-param-reassign @@ -5064,7 +5086,6 @@ function buildOptimisticChatReport( lastMessageText: undefined, lastReadTime: currentTime, lastVisibleActionCreated: currentTime, - notificationPreference, oldPolicyName, ownerAccountID: ownerAccountID || CONST.REPORT.OWNER_ACCOUNT_ID_FAKE, parentReportActionID, @@ -5482,9 +5503,7 @@ function buildOptimisticWorkspaceChats(policyID: string, policyName: string, exp policyName, undefined, undefined, - - // #announce contains all policy members so notifying always should be opt-in only. - CONST.REPORT.NOTIFICATION_PREFERENCE.DAILY, + CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS, ); const announceChatReportID = announceChatData.reportID; const announceCreatedAction = buildOptimisticCreatedReportAction(CONST.POLICY.OWNER_EMAIL_FAKE); @@ -5571,12 +5590,12 @@ function buildOptimisticTaskReport( ): OptimisticTaskReport { const participants: Participants = { [ownerAccountID]: { - hidden: false, + notificationPreference, }, }; if (assigneeAccountID) { - participants[assigneeAccountID] = {hidden: false}; + participants[assigneeAccountID] = {notificationPreference}; } return { @@ -5591,7 +5610,6 @@ function buildOptimisticTaskReport( policyID, stateNum: CONST.REPORT.STATE_NUM.OPEN, statusNum: CONST.REPORT.STATUS_NUM.OPEN, - notificationPreference, lastVisibleActionCreated: DateUtils.getDBTime(), hasParentAccess: true, }; @@ -5669,10 +5687,6 @@ function buildTransactionThread( CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, reportAction?.reportActionID, moneyRequestReport?.reportID, - '', - '', - '', - false, ); } @@ -6049,7 +6063,7 @@ function shouldReportBeInOptionList({ // All unread chats (even archived ones) in GSD mode will be shown. This is because GSD mode is specifically for focusing the user on the most relevant chats, primarily, the unread ones if (isInFocusMode) { - return isUnread(report) && report.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.MUTE; + return isUnread(report) && getReportNotificationPreference(report) !== CONST.REPORT.NOTIFICATION_PREFERENCE.MUTE; } // Archived reports should always be shown when in default (most recent) mode. This is because you should still be able to access and search for the chats to find them. @@ -7441,7 +7455,7 @@ function isAdminOwnerApproverOrReportOwner(report: OnyxEntry, policy: On /** * Whether the user can join a report */ -function canJoinChat(report: OnyxInputOrEntry, parentReportAction: OnyxInputOrEntry, policy: OnyxInputOrEntry): boolean { +function canJoinChat(report: OnyxEntry, parentReportAction: OnyxInputOrEntry, policy: OnyxInputOrEntry): boolean { // We disabled thread functions for whisper action // So we should not show join option for existing thread on whisper message that has already been left, or manually leave it if (ReportActionsUtils.isWhisperAction(parentReportAction)) { @@ -7449,7 +7463,7 @@ function canJoinChat(report: OnyxInputOrEntry, parentReportAction: OnyxI } // If the notification preference of the chat is not hidden that means we have already joined the chat - if (report?.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN) { + if (getReportNotificationPreference(report) !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN) { return false; } @@ -7483,7 +7497,7 @@ function canLeaveChat(report: OnyxEntry, policy: OnyxEntry): boo return false; } - if (report?.notificationPreference === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN) { + if (getReportNotificationPreference(report) === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN) { return false; } @@ -7501,7 +7515,7 @@ function canLeaveChat(report: OnyxEntry, policy: OnyxEntry): boo return canLeaveInvoiceRoom(report); } - return (isChatThread(report) && !!report?.notificationPreference?.length) || isUserCreatedPolicyRoom(report) || isNonAdminOrOwnerOfPolicyExpenseChat(report, policy); + return (isChatThread(report) && !!getReportNotificationPreference(report)) || isUserCreatedPolicyRoom(report) || isNonAdminOrOwnerOfPolicyExpenseChat(report, policy); } function getReportActionActorAccountID(reportAction: OnyxInputOrEntry, iouReport: OnyxInputOrEntry | undefined): number | undefined { @@ -8034,6 +8048,7 @@ export { isInvoiceRoomWithID, isInvoiceReport, isOpenInvoiceReport, + getDefaultNotificationPreferenceForReport, canWriteInReport, navigateToDetailsPage, navigateToPrivateNotes, diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index 1e5965be8d5e..8affc09700ff 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -103,7 +103,7 @@ function getOrderedReportIDs( const reportActions = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`] ?? {}; const parentReportAction = ReportActionsUtils.getReportAction(report?.parentReportID ?? '-1', report?.parentReportActionID ?? '-1'); const doesReportHaveViolations = OptionsListUtils.shouldShowViolations(report, transactionViolations); - const isHidden = report.notificationPreference === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; + const isHidden = ReportUtils.getReportNotificationPreference(report) === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; const isFocused = report.reportID === currentReportId; const allReportErrors = OptionsListUtils.getAllReportErrors(report, reportActions) ?? {}; const transactionReportActions = ReportActionsUtils.getAllReportActions(report.reportID); @@ -343,7 +343,7 @@ function getOptionData({ result.hasOutstandingChildRequest = report.hasOutstandingChildRequest; result.parentReportID = report.parentReportID ?? '-1'; result.isWaitingOnBankAccount = report.isWaitingOnBankAccount; - result.notificationPreference = report.notificationPreference; + result.notificationPreference = ReportUtils.getReportNotificationPreference(report); result.isAllowedToComment = ReportUtils.canUserPerformWriteAction(report); result.chatType = report.chatType; result.isDeletedParentAction = report.isDeletedParentAction; diff --git a/src/libs/UnreadIndicatorUpdater/index.ts b/src/libs/UnreadIndicatorUpdater/index.ts index d6a65ee85aac..f4b8e3281308 100644 --- a/src/libs/UnreadIndicatorUpdater/index.ts +++ b/src/libs/UnreadIndicatorUpdater/index.ts @@ -9,8 +9,9 @@ import type {Report} from '@src/types/onyx'; import updateUnread from './updateUnread'; function getUnreadReportsForUnreadIndicator(reports: OnyxCollection, currentReportID: string) { - return Object.values(reports ?? {}).filter( - (report) => + return Object.values(reports ?? {}).filter((report) => { + const notificationPreference = ReportUtils.getReportNotificationPreference(report); + return ( ReportUtils.isUnread(report) && ReportUtils.shouldReportBeInOptionList({ report, @@ -29,9 +30,10 @@ function getUnreadReportsForUnreadIndicator(reports: OnyxCollection, cur * Furthermore, muted reports may or may not appear in the LHN depending on priority mode, * but they should not be considered in the unread indicator count. */ - report?.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN && - report?.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.MUTE, - ); + notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN && + notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.MUTE + ); + }); } const memoizedGetUnreadReportsForUnreadIndicator = memoize(getUnreadReportsForUnreadIndicator, {maxArgs: 1}); diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index f3c406a8f04e..32e3575f6686 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -3867,7 +3867,7 @@ function getOrCreateOptimisticSplitChatReport(existingSplitChatReportID: string, undefined, undefined, undefined, - CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, + CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS, ); return {existingSplitChatReport: null, splitChatReport}; } @@ -3967,11 +3967,6 @@ function createSplitsAndOnyxData( splitChatReport.lastActorAccountID = currentUserAccountID; splitChatReport.lastVisibleActionCreated = splitIOUReportAction.created; - let splitChatReportNotificationPreference = splitChatReport.notificationPreference; - if (splitChatReportNotificationPreference === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN) { - splitChatReportNotificationPreference = CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS; - } - // If we have an existing splitChatReport (group chat or workspace) use it's pending fields, otherwise indicate that we are adding a chat if (!existingSplitChatReport) { splitChatReport.pendingFields = { @@ -3985,10 +3980,7 @@ function createSplitsAndOnyxData( // and we need the data to be available when we navigate to the chat page onyxMethod: existingSplitChatReport ? Onyx.METHOD.MERGE : Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.REPORT}${splitChatReport.reportID}`, - value: { - ...splitChatReport, - notificationPreference: splitChatReportNotificationPreference, - }, + value: splitChatReport, }, { onyxMethod: Onyx.METHOD.SET, diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index e9703d48d947..147b07f650b2 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -493,7 +493,9 @@ function addActions(reportID: string, text = '', file?: FileObject) { const shouldUpdateNotificationPrefernece = !isEmptyObject(report) && ReportUtils.getReportNotificationPreference(report) === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; if (shouldUpdateNotificationPrefernece) { - optimisticReport.notificationPreference = CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS; + optimisticReport.participants = { + [currentUserAccountID]: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + }; } // Optimistically add the new actions to the store before waiting to save them to the server @@ -553,7 +555,9 @@ function addActions(reportID: string, text = '', file?: FileObject) { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, value: { - notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS, + participants: { + [currentUserAccountID]: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + }, }, }); } @@ -1007,7 +1011,7 @@ function navigateToAndOpenReport( if (isEmptyObject(chat)) { if (isGroupChat) { // If we are creating a group chat then participantAccountIDs is expected to contain currentUserAccountID - newChat = ReportUtils.buildOptimisticGroupChatReport(participantAccountIDs, reportName ?? '', avatarUri ?? '', optimisticReportID, CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN); + newChat = ReportUtils.buildOptimisticGroupChatReport(participantAccountIDs, reportName ?? '', avatarUri ?? '', optimisticReportID, CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS); } else { newChat = ReportUtils.buildOptimisticChatReport( [...participantAccountIDs, currentUserAccountID], @@ -1019,7 +1023,7 @@ function navigateToAndOpenReport( undefined, undefined, undefined, - CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, + CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS, ); } } @@ -1696,7 +1700,6 @@ function updateNotificationPreference( parentReportID?: string, parentReportActionID?: string, report?: OnyxEntry, - isJoiningRoom?: boolean, ) { if (previousValue === newValue) { if (navigate && !isEmptyObject(report) && report.reportID) { @@ -1709,7 +1712,13 @@ function updateNotificationPreference( { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, - value: {notificationPreference: newValue}, + value: { + participants: { + [currentUserAccountID]: { + notificationPreference: newValue, + }, + }, + }, }, ]; @@ -1717,7 +1726,13 @@ function updateNotificationPreference( { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, - value: {notificationPreference: previousValue}, + value: { + participants: { + [currentUserAccountID]: { + notificationPreference: previousValue, + }, + }, + }, }, ]; @@ -1734,20 +1749,6 @@ function updateNotificationPreference( }); } - if (isJoiningRoom) { - optimisticData.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, - value: { - participants: { - [currentUserAccountID]: { - hidden: false, - }, - }, - }, - }); - } - const parameters: UpdateReportNotificationPreferenceParams = {reportID, notificationPreference: newValue}; API.write(WRITE_COMMANDS.UPDATE_REPORT_NOTIFICATION_PREFERENCE, parameters, {optimisticData, failureData}); @@ -2417,7 +2418,7 @@ function shouldShowReportActionNotification(reportID: string, action: ReportActi } // We don't want to send a local notification if the user preference is daily, mute or hidden. - const notificationPreference = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]?.notificationPreference ?? CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS; + const notificationPreference = ReportUtils.getReportNotificationPreference(ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]); if (notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS) { Log.info(`${tag} No notification because user preference is to be notified: ${notificationPreference}`); return false; @@ -2749,13 +2750,12 @@ function joinRoom(report: OnyxEntry) { } updateNotificationPreference( report.reportID, - report.notificationPreference, + ReportUtils.getReportNotificationPreference(report), CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS, false, report.parentReportID, report.parentReportActionID, report, - true, ); } @@ -2810,10 +2810,9 @@ function leaveRoom(reportID: string, isWorkspaceMemberLeavingWorkspaceRoom = fal value: isWorkspaceMemberLeavingWorkspaceRoom || isChatThread ? { - notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, participants: { [currentUserAccountID]: { - hidden: true, + notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, }, }, } @@ -2821,7 +2820,11 @@ function leaveRoom(reportID: string, isWorkspaceMemberLeavingWorkspaceRoom = fal reportID: null, stateNum: CONST.REPORT.STATE_NUM.APPROVED, statusNum: CONST.REPORT.STATUS_NUM.CLOSED, - notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, + participants: { + [currentUserAccountID]: { + notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, + }, + }, }, }, ]; @@ -2832,7 +2835,13 @@ function leaveRoom(reportID: string, isWorkspaceMemberLeavingWorkspaceRoom = fal key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, value: isWorkspaceMemberLeavingWorkspaceRoom || isChatThread - ? {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN} + ? { + participants: { + [currentUserAccountID]: { + notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, + }, + }, + } : Object.keys(report).reduce>((acc, key) => { acc[key] = null; return acc; @@ -2862,7 +2871,7 @@ function leaveRoom(reportID: string, isWorkspaceMemberLeavingWorkspaceRoom = fal failureData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`, - value: {[report.parentReportActionID]: {childReportNotificationPreference: report.notificationPreference}}, + value: {[report.parentReportActionID]: {childReportNotificationPreference: ReportUtils.getReportNotificationPreference(report)}}, }); } @@ -2888,6 +2897,8 @@ function inviteToRoom(reportID: string, inviteeEmailsToAccountIDs: InvitedEmails return; } + const defaultNotificationPreference = ReportUtils.getDefaultNotificationPreferenceForReport(report); + const inviteeEmails = Object.keys(inviteeEmailsToAccountIDs); const inviteeAccountIDs = Object.values(inviteeEmailsToAccountIDs); @@ -2897,7 +2908,7 @@ function inviteToRoom(reportID: string, inviteeEmailsToAccountIDs: InvitedEmails const participantsAfterInvitation = inviteeAccountIDs.reduce( (reportParticipants: Participants, accountID: number) => { const participant: ReportParticipant = { - hidden: false, + notificationPreference: defaultNotificationPreference, role: CONST.REPORT.ROLE.MEMBER, }; // eslint-disable-next-line no-param-reassign @@ -3000,8 +3011,8 @@ function clearAddRoomMemberError(reportID: string, invitedAccountID: string) { function updateGroupChatMemberRoles(reportID: string, accountIDList: number[], role: ValueOf) { const memberRoles: Record = {}; - const optimisticParticipants: Participants = {}; - const successParticipants: Participants = {}; + const optimisticParticipants: Record> = {}; + const successParticipants: Record> = {}; accountIDList.forEach((accountID) => { memberRoles[accountID] = role; diff --git a/src/libs/actions/Task.ts b/src/libs/actions/Task.ts index dc3b6781ee83..b2ac3992023e 100644 --- a/src/libs/actions/Task.ts +++ b/src/libs/actions/Task.ts @@ -25,7 +25,7 @@ import type ReportAction from '@src/types/onyx/ReportAction'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import * as Report from './Report'; -type OptimisticReport = Pick; +type OptimisticReport = Pick; type Assignee = { icons: Icon[]; displayName: string; @@ -581,9 +581,13 @@ function editTaskAssignee(report: OnyxTypes.Report, ownerAccountID: number, assi pendingFields: { ...(assigneeAccountID && {managerID: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}), }, - notificationPreference: [assigneeAccountID, ownerAccountID].includes(currentUserAccountID) - ? CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS - : CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, + participants: { + [currentUserAccountID]: { + notificationPreference: [assigneeAccountID, ownerAccountID].includes(currentUserAccountID) + ? CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS + : CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, + }, + }, }; const successReport: NullishDeep = {pendingFields: {...(assigneeAccountID && {managerID: null})}}; @@ -662,7 +666,12 @@ function editTaskAssignee(report: OnyxTypes.Report, ownerAccountID: number, assi // If we make a change to the assignee, we want to add a comment to the assignee's chat // Check if the assignee actually changed if (assigneeAccountID && assigneeAccountID !== report.managerID && assigneeAccountID !== ownerAccountID && assigneeChatReport) { - optimisticReport.participants = {[assigneeAccountID]: {hidden: false}}; + optimisticReport.participants = { + ...(optimisticReport.participants ?? {}), + [assigneeAccountID]: { + notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS, + }, + }; assigneeChatReportOnyxData = ReportUtils.getTaskAssigneeChatOnyxData( currentUserAccountID, diff --git a/src/libs/actions/User.ts b/src/libs/actions/User.ts index 04d57e52be47..c87721728a3d 100644 --- a/src/libs/actions/User.ts +++ b/src/libs/actions/User.ts @@ -678,11 +678,10 @@ const isChannelMuted = (reportId: string) => key: `${ONYXKEYS.COLLECTION.REPORT}${reportId}`, callback: (report) => { Onyx.disconnect(connection); + const notificationPreference = report?.participants?.[currentUserAccountID]?.notificationPreference; resolve( - !report?.notificationPreference || - report?.notificationPreference === CONST.REPORT.NOTIFICATION_PREFERENCE.MUTE || - report?.notificationPreference === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, + !notificationPreference || notificationPreference === CONST.REPORT.NOTIFICATION_PREFERENCE.MUTE || notificationPreference === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, ); }, }); diff --git a/src/pages/ProfilePage.tsx b/src/pages/ProfilePage.tsx index 8b12ae4b63ab..9cda6901fdfe 100755 --- a/src/pages/ProfilePage.tsx +++ b/src/pages/ProfilePage.tsx @@ -155,10 +155,11 @@ function ProfilePage({route}: ProfilePageProps) { const navigateBackTo = route?.params?.backTo; - const shouldShowNotificationPreference = - !isEmptyObject(report) && !isCurrentUser && !!report.notificationPreference && report.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; + const notificationPreferenceValue = ReportUtils.getReportNotificationPreference(report); + + const shouldShowNotificationPreference = !isEmptyObject(report) && !isCurrentUser && notificationPreferenceValue !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; const notificationPreference = shouldShowNotificationPreference - ? translate(`notificationPreferencesPage.notificationPreferences.${report.notificationPreference}` as TranslationPaths) + ? translate(`notificationPreferencesPage.notificationPreferences.${notificationPreferenceValue}` as TranslationPaths) : ''; // eslint-disable-next-line rulesdir/prefer-early-return diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index aa419faedc29..88f856c630cc 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -268,7 +268,7 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD roomDescription = translate('newRoomPage.roomName'); } - const shouldShowNotificationPref = !isMoneyRequestReport && report?.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; + const shouldShowNotificationPref = !isMoneyRequestReport && ReportUtils.getReportNotificationPreference(report) !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; const shouldShowWriteCapability = !isMoneyRequestReport; const shouldShowMenuItem = shouldShowNotificationPref || shouldShowWriteCapability || (!!report?.visibility && report.chatType !== CONST.REPORT.CHAT_TYPE.INVOICE); diff --git a/src/pages/RoomInvitePage.tsx b/src/pages/RoomInvitePage.tsx index 17239e6d4fb5..5dc281d8013e 100644 --- a/src/pages/RoomInvitePage.tsx +++ b/src/pages/RoomInvitePage.tsx @@ -66,7 +66,7 @@ function RoomInvitePage({ // Any existing participants and Expensify emails should not be eligible for invitation const excludedUsers = useMemo(() => { const visibleParticipantAccountIDs = Object.entries(report.participants ?? {}) - .filter(([, participant]) => participant && !participant.hidden) + .filter(([, participant]) => participant && participant.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN) .map(([accountID]) => Number(accountID)); return [...PersonalDetailsUtils.getLoginsByAccountIDs(visibleParticipantAccountIDs), ...CONST.EXPENSIFY_EMAILS].map((participant) => PhoneNumber.addSMSDomainIfPhoneNumber(participant), diff --git a/src/pages/home/ReportScreen.tsx b/src/pages/home/ReportScreen.tsx index 9e8c46692bbd..4eaf3633af38 100644 --- a/src/pages/home/ReportScreen.tsx +++ b/src/pages/home/ReportScreen.tsx @@ -196,7 +196,6 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro isWaitingOnBankAccount: reportOnyx?.isWaitingOnBankAccount, iouReportID: reportOnyx?.iouReportID, isOwnPolicyExpenseChat: reportOnyx?.isOwnPolicyExpenseChat, - notificationPreference: reportOnyx?.notificationPreference, isPinned: reportOnyx?.isPinned, chatReportID: reportOnyx?.chatReportID, visibility: reportOnyx?.visibility, @@ -240,7 +239,6 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro reportOnyx?.isWaitingOnBankAccount, reportOnyx?.iouReportID, reportOnyx?.isOwnPolicyExpenseChat, - reportOnyx?.notificationPreference, reportOnyx?.isPinned, reportOnyx?.chatReportID, reportOnyx?.visibility, @@ -550,7 +548,7 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro !isFocused || prevIsFocused || !ReportUtils.isChatThread(report) || - report.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN || + ReportUtils.getReportNotificationPreference(report) !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN || isSingleTransactionView ) { return; @@ -560,7 +558,7 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro // 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. // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps - }, [prevIsFocused, report.notificationPreference, isFocused, isSingleTransactionView]); + }, [prevIsFocused, report.participants, isFocused, isSingleTransactionView]); useEffect(() => { // We don't want this effect to run on the first render. diff --git a/src/pages/settings/Report/NotificationPreferencePage.tsx b/src/pages/settings/Report/NotificationPreferencePage.tsx index 3a149e1ed377..fd256d685139 100644 --- a/src/pages/settings/Report/NotificationPreferencePage.tsx +++ b/src/pages/settings/Report/NotificationPreferencePage.tsx @@ -22,17 +22,18 @@ function NotificationPreferencePage({report}: NotificationPreferencePageProps) { const {translate} = useLocalize(); const [reportNameValuePairs] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report.reportID || -1}`); const isMoneyRequestReport = ReportUtils.isMoneyRequestReport(report); + const currentNotificationPreference = ReportUtils.getReportNotificationPreference(report); const shouldDisableNotificationPreferences = ReportUtils.isArchivedRoom(report, reportNameValuePairs) || ReportUtils.isSelfDM(report) || - (!isMoneyRequestReport && report?.notificationPreference === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN); + (!isMoneyRequestReport && currentNotificationPreference === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN); const notificationPreferenceOptions = Object.values(CONST.REPORT.NOTIFICATION_PREFERENCE) .filter((pref) => pref !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN) .map((preference) => ({ value: preference, text: translate(`notificationPreferencesPage.notificationPreferences.${preference}`), keyForList: preference, - isSelected: preference === report?.notificationPreference, + isSelected: preference === currentNotificationPreference, })); return ( @@ -49,7 +50,7 @@ function NotificationPreferencePage({report}: NotificationPreferencePageProps) { sections={[{data: notificationPreferenceOptions}]} ListItem={RadioListItem} onSelectRow={(option) => - report && ReportActions.updateNotificationPreference(report.reportID, report.notificationPreference, option.value, true, undefined, undefined, report) + report && ReportActions.updateNotificationPreference(report.reportID, currentNotificationPreference, option.value, true, undefined, undefined, report) } shouldSingleExecuteRowSelect initiallyFocusedOptionKey={notificationPreferenceOptions.find((locale) => locale.isSelected)?.keyForList} diff --git a/src/pages/settings/Report/ReportSettingsPage.tsx b/src/pages/settings/Report/ReportSettingsPage.tsx index 6e1ab9a61737..6a9986b5550f 100644 --- a/src/pages/settings/Report/ReportSettingsPage.tsx +++ b/src/pages/settings/Report/ReportSettingsPage.tsx @@ -33,9 +33,10 @@ function ReportSettingsPage({report, policies}: ReportSettingsPageProps) { const isMoneyRequestReport = ReportUtils.isMoneyRequestReport(report); const shouldDisableSettings = isEmptyObject(report) || ReportUtils.isArchivedRoom(report, reportNameValuePairs) || ReportUtils.isSelfDM(report); + const notificationPreferenceValue = ReportUtils.getReportNotificationPreference(report); const notificationPreference = - report?.notificationPreference && report.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN - ? translate(`notificationPreferencesPage.notificationPreferences.${report.notificationPreference}`) + notificationPreferenceValue && notificationPreferenceValue !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN + ? translate(`notificationPreferencesPage.notificationPreferences.${notificationPreferenceValue}`) : ''; const writeCapability = ReportUtils.isAdminRoom(report) ? CONST.REPORT.WRITE_CAPABILITIES.ADMINS : report?.writeCapability ?? CONST.REPORT.WRITE_CAPABILITIES.ALL; @@ -43,7 +44,7 @@ function ReportSettingsPage({report, policies}: ReportSettingsPageProps) { const shouldAllowWriteCapabilityEditing = useMemo(() => ReportUtils.canEditWriteCapability(report, linkedWorkspace), [report, linkedWorkspace]); const shouldAllowChangeVisibility = useMemo(() => ReportUtils.canEditRoomVisibility(report, linkedWorkspace), [report, linkedWorkspace]); - const shouldShowNotificationPref = !isMoneyRequestReport && report?.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; + const shouldShowNotificationPref = !isMoneyRequestReport && notificationPreferenceValue !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; const shouldShowWriteCapability = !isMoneyRequestReport; diff --git a/src/types/onyx/Report.ts b/src/types/onyx/Report.ts index 0a545cb8e4dc..b92f38f29ee1 100644 --- a/src/types/onyx/Report.ts +++ b/src/types/onyx/Report.ts @@ -39,7 +39,7 @@ type PendingChatMember = { /** Report participant properties */ type Participant = OnyxCommon.OnyxValueWithOfflineFeedback<{ /** Whether the participant is visible in the report */ - hidden?: boolean; + notificationPreference: NotificationPreference; /** What is the role of the participant in the report */ role?: 'admin' | 'member'; @@ -113,9 +113,6 @@ type Report = OnyxCommon.OnyxValueWithOfflineFeedback< /** The time of the last mention of the report */ lastMentionedTime?: string | null; - /** The current user's notification preference for this report */ - notificationPreference?: NotificationPreference; - /** The policy avatar to use, if any */ policyAvatar?: string | null; diff --git a/tests/actions/IOUTest.ts b/tests/actions/IOUTest.ts index 8a7095af6f7f..662eae8d7b21 100644 --- a/tests/actions/IOUTest.ts +++ b/tests/actions/IOUTest.ts @@ -38,16 +38,16 @@ jest.mock('@src/libs/Navigation/isSearchTopmostCentralPane', () => jest.fn()); const CARLOS_EMAIL = 'cmartins@expensifail.com'; const CARLOS_ACCOUNT_ID = 1; -const CARLOS_PARTICIPANT: Participant = {hidden: false, role: 'member'}; +const CARLOS_PARTICIPANT: Participant = {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS, role: 'member'}; const JULES_EMAIL = 'jules@expensifail.com'; const JULES_ACCOUNT_ID = 2; -const JULES_PARTICIPANT: Participant = {hidden: false, role: 'member'}; +const JULES_PARTICIPANT: Participant = {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS, role: 'member'}; const RORY_EMAIL = 'rory@expensifail.com'; const RORY_ACCOUNT_ID = 3; -const RORY_PARTICIPANT: Participant = {hidden: false, role: 'admin'}; +const RORY_PARTICIPANT: Participant = {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS, role: 'admin'}; const VIT_EMAIL = 'vit@expensifail.com'; const VIT_ACCOUNT_ID = 4; -const VIT_PARTICIPANT: Participant = {hidden: false, role: 'member'}; +const VIT_PARTICIPANT: Participant = {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS, role: 'member'}; OnyxUpdateManager(); describe('actions/IOU', () => { @@ -102,7 +102,10 @@ describe('actions/IOU', () => { iouReportID = iouReport?.reportID; transactionThread = transactionThreadReport; - expect(iouReport?.notificationPreference).toBe(CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN); + expect(iouReport?.participants).toEqual({ + [RORY_ACCOUNT_ID]: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN}, + [CARLOS_ACCOUNT_ID]: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN}, + }); // They should be linked together expect(chatReport?.participants).toEqual({[RORY_ACCOUNT_ID]: RORY_PARTICIPANT, [CARLOS_ACCOUNT_ID]: CARLOS_PARTICIPANT}); @@ -295,7 +298,10 @@ describe('actions/IOU', () => { const iouReport = Object.values(allReports ?? {}).find((report) => report?.type === CONST.REPORT.TYPE.IOU); iouReportID = iouReport?.reportID; - expect(iouReport?.notificationPreference).toBe(CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN); + expect(iouReport?.participants).toEqual({ + [RORY_ACCOUNT_ID]: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN}, + [CARLOS_ACCOUNT_ID]: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN}, + }); // They should be linked together expect(chatReport.iouReportID).toBe(iouReportID); @@ -640,10 +646,10 @@ describe('actions/IOU', () => { const iouReport = iouReports[0]; iouReportID = iouReport?.reportID; - expect(iouReport?.notificationPreference).toBe(CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN); + expect(chatReport?.participants).toStrictEqual({[RORY_ACCOUNT_ID]: RORY_PARTICIPANT, [CARLOS_ACCOUNT_ID]: CARLOS_PARTICIPANT}); // They should be linked together - expect(chatReport?.participants).toEqual({[RORY_ACCOUNT_ID]: RORY_PARTICIPANT, [CARLOS_ACCOUNT_ID]: CARLOS_PARTICIPANT}); + expect(chatReport?.participants).toStrictEqual({[RORY_ACCOUNT_ID]: RORY_PARTICIPANT, [CARLOS_ACCOUNT_ID]: CARLOS_PARTICIPANT}); expect(chatReport?.iouReportID).toBe(iouReport?.reportID); resolve(); @@ -1161,14 +1167,15 @@ describe('actions/IOU', () => { // The 1:1 chat reports and the IOU reports should be linked together expect(carlosChatReport?.iouReportID).toBe(carlosIOUReport?.reportID); expect(carlosIOUReport?.chatReportID).toBe(carlosChatReport?.reportID); - expect(carlosIOUReport?.notificationPreference).toBe(CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN); + Object.values(carlosIOUReport?.participants ?? {}).forEach((participant) => { + expect(participant.notificationPreference).toBe(CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN); + }); expect(julesChatReport?.iouReportID).toBe(julesIOUReport?.reportID); expect(julesIOUReport?.chatReportID).toBe(julesChatReport?.reportID); expect(vitChatReport?.iouReportID).toBe(vitIOUReport?.reportID); expect(vitIOUReport?.chatReportID).toBe(vitChatReport?.reportID); - expect(carlosIOUReport?.notificationPreference).toBe(CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN); resolve(); }, @@ -2439,7 +2446,7 @@ describe('actions/IOU', () => { // Given a transaction thread thread = ReportUtils.buildTransactionThread(createIOUAction, iouReport); - expect(thread.notificationPreference).toBe(CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN); + expect(thread.participants).toStrictEqual({[CARLOS_ACCOUNT_ID]: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, role: CONST.REPORT.ROLE.ADMIN}}); Onyx.connect({ key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${thread.reportID}`, @@ -2628,7 +2635,7 @@ describe('actions/IOU', () => { // Given a transaction thread thread = ReportUtils.buildTransactionThread(createIOUAction, iouReport); - expect(thread.notificationPreference).toBe(CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN); + expect(thread.participants).toEqual({[CARLOS_ACCOUNT_ID]: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, role: CONST.REPORT.ROLE.ADMIN}}); const participantAccountIDs = Object.keys(thread.participants ?? {}).map(Number); const userLogins = PersonalDetailsUtils.getLoginsByAccountIDs(participantAccountIDs); @@ -2716,7 +2723,7 @@ describe('actions/IOU', () => { jest.advanceTimersByTime(10); thread = ReportUtils.buildTransactionThread(createIOUAction, iouReport); - expect(thread.notificationPreference).toBe(CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN); + expect(thread.participants).toStrictEqual({[CARLOS_ACCOUNT_ID]: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, role: CONST.REPORT.ROLE.ADMIN}}); Onyx.connect({ key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${thread.reportID}`, @@ -2956,7 +2963,7 @@ describe('actions/IOU', () => { jest.advanceTimersByTime(10); thread = ReportUtils.buildTransactionThread(createIOUAction, iouReport); - expect(thread.notificationPreference).toBe(CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN); + expect(thread.participants).toStrictEqual({[CARLOS_ACCOUNT_ID]: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, role: CONST.REPORT.ROLE.ADMIN}}); Onyx.connect({ key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${thread.reportID}`, diff --git a/tests/actions/PolicyTest.ts b/tests/actions/PolicyTest.ts index a9af7b9da7d8..01842b48b6f4 100644 --- a/tests/actions/PolicyTest.ts +++ b/tests/actions/PolicyTest.ts @@ -12,7 +12,9 @@ import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; const ESH_EMAIL = 'eshgupta1217@gmail.com'; const ESH_ACCOUNT_ID = 1; -const ESH_PARTICIPANT: Participant = {hidden: false}; +const ESH_PARTICIPANT_ANNOUNCE_ROOM: Participant = {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}; +const ESH_PARTICIPANT_ADMINS_ROOM: Participant = {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}; +const ESH_PARTICIPANT_EXPENSE_CHAT = {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}; const WORKSPACE_NAME = "Esh's Workspace"; OnyxUpdateManager(); @@ -78,17 +80,19 @@ describe('actions/Policy', () => { expect(workspaceReports.length).toBe(3); workspaceReports.forEach((report) => { expect(report?.pendingFields?.addWorkspaceRoom).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); - expect(report?.participants).toEqual({[ESH_ACCOUNT_ID]: ESH_PARTICIPANT}); switch (report?.chatType) { case CONST.REPORT.CHAT_TYPE.POLICY_ADMINS: { + expect(report?.participants).toEqual({[ESH_ACCOUNT_ID]: ESH_PARTICIPANT_ADMINS_ROOM}); adminReportID = report.reportID; break; } case CONST.REPORT.CHAT_TYPE.POLICY_ANNOUNCE: { + expect(report?.participants).toEqual({[ESH_ACCOUNT_ID]: ESH_PARTICIPANT_ANNOUNCE_ROOM}); announceReportID = report.reportID; break; } case CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT: { + expect(report?.participants).toEqual({[ESH_ACCOUNT_ID]: ESH_PARTICIPANT_EXPENSE_CHAT}); expenseReportID = report.reportID; break; } diff --git a/tests/actions/ReportTest.ts b/tests/actions/ReportTest.ts index e6ab31334bb1..a099348257f0 100644 --- a/tests/actions/ReportTest.ts +++ b/tests/actions/ReportTest.ts @@ -103,7 +103,11 @@ describe('actions/Report', () => { key: `${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, value: { reportID: REPORT_ID, - notificationPreference: 'always', + participants: { + [TEST_USER_ACCOUNT_ID]: { + notificationPreference: 'always', + }, + }, lastVisibleActionCreated: '2022-11-22 03:48:27.267', lastMessageText: 'Testing a comment', lastActorAccountID: TEST_USER_ACCOUNT_ID, @@ -230,7 +234,11 @@ describe('actions/Report', () => { key: `${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, value: { reportID: REPORT_ID, - notificationPreference: 'always', + participants: { + [USER_1_ACCOUNT_ID]: { + notificationPreference: 'always', + }, + }, lastMessageText: 'Comment 1', lastActorAccountID: USER_2_ACCOUNT_ID, lastVisibleActionCreated: reportActionCreatedDate, @@ -380,7 +388,11 @@ describe('actions/Report', () => { key: `${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, value: { reportID: REPORT_ID, - notificationPreference: 'always', + participants: { + [USER_1_ACCOUNT_ID]: { + notificationPreference: 'always', + }, + }, lastMessageText: 'Current User Comment 3', lastActorAccountID: 1, lastVisibleActionCreated: reportActionCreatedDate, diff --git a/tests/ui/PaginationTest.tsx b/tests/ui/PaginationTest.tsx index 44ad43e69953..6e867fbb239b 100644 --- a/tests/ui/PaginationTest.tsx +++ b/tests/ui/PaginationTest.tsx @@ -198,7 +198,7 @@ async function signInAndGetApp(): Promise { reportID: REPORT_ID, reportName: CONST.REPORT.DEFAULT_REPORT_NAME, lastMessageText: 'Test', - participants: {[USER_B_ACCOUNT_ID]: {hidden: false}}, + participants: {[USER_B_ACCOUNT_ID]: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}}, lastActorAccountID: USER_B_ACCOUNT_ID, type: CONST.REPORT.TYPE.CHAT, }); @@ -212,7 +212,7 @@ async function signInAndGetApp(): Promise { reportID: COMMENT_LINKING_REPORT_ID, reportName: CONST.REPORT.DEFAULT_REPORT_NAME, lastMessageText: 'Test', - participants: {[USER_A_ACCOUNT_ID]: {hidden: false}}, + participants: {[USER_A_ACCOUNT_ID]: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}}, lastActorAccountID: USER_A_ACCOUNT_ID, type: CONST.REPORT.TYPE.CHAT, }); diff --git a/tests/ui/UnreadIndicatorsTest.tsx b/tests/ui/UnreadIndicatorsTest.tsx index 1d31a707d81d..011f1e01668f 100644 --- a/tests/ui/UnreadIndicatorsTest.tsx +++ b/tests/ui/UnreadIndicatorsTest.tsx @@ -140,7 +140,7 @@ function signInAndGetAppWithUnreadChat(): Promise { lastReadTime: reportAction3CreatedDate, lastVisibleActionCreated: reportAction9CreatedDate, lastMessageText: 'Test', - participants: {[USER_B_ACCOUNT_ID]: {hidden: false}}, + participants: {[USER_B_ACCOUNT_ID]: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}}, lastActorAccountID: USER_B_ACCOUNT_ID, type: CONST.REPORT.TYPE.CHAT, }); @@ -301,7 +301,7 @@ describe('Unread Indicators', () => { lastVisibleActionCreated: DateUtils.getDBTime(utcToZonedTime(NEW_REPORT_FIST_MESSAGE_CREATED_DATE, 'UTC').valueOf()), lastMessageText: 'Comment 1', lastActorAccountID: USER_C_ACCOUNT_ID, - participants: {[USER_C_ACCOUNT_ID]: {hidden: false}}, + participants: {[USER_C_ACCOUNT_ID]: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}}, type: CONST.REPORT.TYPE.CHAT, }, }, diff --git a/tests/unit/OptionsListUtilsTest.ts b/tests/unit/OptionsListUtilsTest.ts index c2beebfa563d..6247dbba1f50 100644 --- a/tests/unit/OptionsListUtilsTest.ts +++ b/tests/unit/OptionsListUtilsTest.ts @@ -22,9 +22,9 @@ describe('OptionsListUtils', () => { isPinned: false, reportID: '1', participants: { - 2: {}, - 1: {}, - 5: {}, + 2: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + 1: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + 5: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, }, reportName: 'Iron Man, Mister Fantastic, Invisible Woman', type: CONST.REPORT.TYPE.CHAT, @@ -35,8 +35,8 @@ describe('OptionsListUtils', () => { isPinned: false, reportID: '2', participants: { - 2: {}, - 3: {}, + 2: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + 3: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, }, reportName: 'Spider-Man', type: CONST.REPORT.TYPE.CHAT, @@ -49,8 +49,8 @@ describe('OptionsListUtils', () => { isPinned: true, reportID: '3', participants: { - 2: {}, - 1: {}, + 2: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + 1: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, }, reportName: 'Mister Fantastic', type: CONST.REPORT.TYPE.CHAT, @@ -61,8 +61,8 @@ describe('OptionsListUtils', () => { isPinned: false, reportID: '4', participants: { - 2: {}, - 4: {}, + 2: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + 4: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, }, reportName: 'Black Panther', type: CONST.REPORT.TYPE.CHAT, @@ -73,8 +73,8 @@ describe('OptionsListUtils', () => { isPinned: false, reportID: '5', participants: { - 2: {}, - 5: {}, + 2: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + 5: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, }, reportName: 'Invisible Woman', type: CONST.REPORT.TYPE.CHAT, @@ -85,8 +85,8 @@ describe('OptionsListUtils', () => { isPinned: false, reportID: '6', participants: { - 2: {}, - 6: {}, + 2: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + 6: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, }, reportName: 'Thor', type: CONST.REPORT.TYPE.CHAT, @@ -99,8 +99,8 @@ describe('OptionsListUtils', () => { isPinned: false, reportID: '7', participants: { - 2: {}, - 7: {}, + 2: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + 7: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, }, reportName: 'Captain America', type: CONST.REPORT.TYPE.CHAT, @@ -113,8 +113,8 @@ describe('OptionsListUtils', () => { isPinned: false, reportID: '8', participants: { - 2: {}, - 12: {}, + 2: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + 12: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, }, reportName: 'Silver Surfer', type: CONST.REPORT.TYPE.CHAT, @@ -127,8 +127,8 @@ describe('OptionsListUtils', () => { isPinned: false, reportID: '9', participants: { - 2: {}, - 8: {}, + 2: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + 8: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, }, reportName: 'Mister Sinister', iouReportID: '100', @@ -142,8 +142,8 @@ describe('OptionsListUtils', () => { reportID: '10', isPinned: false, participants: { - 2: {}, - 7: {}, + 2: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + 7: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, }, reportName: '', oldPolicyName: "SHIELD's workspace", @@ -236,8 +236,8 @@ describe('OptionsListUtils', () => { isPinned: false, reportID: '11', participants: { - 2: {}, - 999: {}, + 2: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + 999: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, }, reportName: 'Concierge', type: CONST.REPORT.TYPE.CHAT, @@ -252,8 +252,8 @@ describe('OptionsListUtils', () => { isPinned: false, reportID: '12', participants: { - 2: {}, - 1000: {}, + 2: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + 1000: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, }, reportName: 'Chronos', type: CONST.REPORT.TYPE.CHAT, @@ -268,8 +268,8 @@ describe('OptionsListUtils', () => { isPinned: false, reportID: '13', participants: { - 2: {}, - 1001: {}, + 2: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + 1001: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, }, reportName: 'Receipts', type: CONST.REPORT.TYPE.CHAT, @@ -284,10 +284,10 @@ describe('OptionsListUtils', () => { isPinned: false, reportID: '14', participants: { - 2: {}, - 1: {}, - 10: {}, - 3: {}, + 2: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + 1: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + 10: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + 3: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, }, reportName: '', oldPolicyName: 'Avengers Room', @@ -305,9 +305,9 @@ describe('OptionsListUtils', () => { isPinned: false, reportID: '15', participants: { - 2: {}, - 3: {}, - 4: {}, + 2: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + 3: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + 4: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, }, reportName: 'Spider-Man, Black Panther', type: CONST.REPORT.TYPE.CHAT, diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts index bdff4323579f..2008cf45b746 100644 --- a/tests/unit/ReportUtilsTest.ts +++ b/tests/unit/ReportUtilsTest.ts @@ -954,28 +954,44 @@ describe('ReportUtils', () => { const invoiceReport: Report = { reportID: '1', type: CONST.REPORT.TYPE.INVOICE, - participants: {[userAccountID]: {hidden: false}, [currentUserAccountID]: {hidden: false}}, + participants: { + [userAccountID]: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + [currentUserAccountID]: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + }, }; const taskReport: Report = { reportID: '2', type: CONST.REPORT.TYPE.TASK, - participants: {[userAccountID]: {hidden: false}, [currentUserAccountID]: {hidden: false}}, + participants: { + [userAccountID]: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + [currentUserAccountID]: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + }, }; const iouReport: Report = { reportID: '3', type: CONST.REPORT.TYPE.IOU, - participants: {[userAccountID]: {hidden: false}, [currentUserAccountID]: {hidden: false}}, + participants: { + [userAccountID]: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + [currentUserAccountID]: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + }, }; groupChatReport = { reportID: '4', type: CONST.REPORT.TYPE.CHAT, chatType: CONST.REPORT.CHAT_TYPE.GROUP, - participants: {[userAccountID]: {hidden: false}, [userAccountID2]: {hidden: false}, [currentUserAccountID]: {hidden: false}}, + participants: { + [userAccountID]: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + [userAccountID2]: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + [currentUserAccountID]: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + }, }; oneOnOneChatReport = { reportID: '5', type: CONST.REPORT.TYPE.CHAT, - participants: {[userAccountID]: {hidden: false}, [currentUserAccountID]: {hidden: false}}, + participants: { + [userAccountID]: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + [currentUserAccountID]: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + }, }; const reportCollectionDataSet = toCollectionDataSet( ONYXKEYS.COLLECTION.REPORT, diff --git a/tests/unit/UnreadIndicatorUpdaterTest.ts b/tests/unit/UnreadIndicatorUpdaterTest.ts index 9cf65bcb69d4..cf8119f3784a 100644 --- a/tests/unit/UnreadIndicatorUpdaterTest.ts +++ b/tests/unit/UnreadIndicatorUpdaterTest.ts @@ -1,6 +1,10 @@ /* eslint-disable @typescript-eslint/naming-convention */ import CONST from '../../src/CONST'; import * as UnreadIndicatorUpdater from '../../src/libs/UnreadIndicatorUpdater'; +import * as TestHelper from '../utils/TestHelper'; + +const TEST_USER_ACCOUNT_ID = 1; +const TEST_USER_LOGIN = 'test@test.com'; describe('UnreadIndicatorUpdaterTest', () => { describe('should return correct number of unread reports', () => { @@ -24,7 +28,9 @@ describe('UnreadIndicatorUpdaterTest', () => { }, 3: {reportID: '3', reportName: 'test', type: CONST.REPORT.TYPE.TASK, lastMessageText: 'test'}, }; - expect(UnreadIndicatorUpdater.getUnreadReportsForUnreadIndicator(reportsToBeUsed, '3').length).toBe(2); + TestHelper.setPersonalDetails(TEST_USER_LOGIN, TEST_USER_ACCOUNT_ID).then(() => { + expect(UnreadIndicatorUpdater.getUnreadReportsForUnreadIndicator(reportsToBeUsed, '3').length).toBe(2); + }); }); it('given some reports are incomplete', () => { @@ -42,7 +48,11 @@ describe('UnreadIndicatorUpdaterTest', () => { reportID: '1', reportName: 'test', type: CONST.REPORT.TYPE.EXPENSE, - notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, + participants: { + [TEST_USER_ACCOUNT_ID]: { + notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, + }, + }, lastReadTime: '2023-07-08 07:15:44.030', lastVisibleActionCreated: '2023-08-08 07:15:44.030', lastMessageText: 'test', @@ -57,7 +67,9 @@ describe('UnreadIndicatorUpdaterTest', () => { }, 3: {reportID: '3', reportName: 'test', type: CONST.REPORT.TYPE.TASK, lastMessageText: 'test'}, }; - expect(UnreadIndicatorUpdater.getUnreadReportsForUnreadIndicator(reportsToBeUsed, '3').length).toBe(1); + TestHelper.setPersonalDetails(TEST_USER_LOGIN, TEST_USER_ACCOUNT_ID).then(() => { + expect(UnreadIndicatorUpdater.getUnreadReportsForUnreadIndicator(reportsToBeUsed, '3').length).toBe(1); + }); }); }); });