Skip to content

Commit 0f49da9

Browse files
authored
Merge pull request Expensify#88543 from dukenv0307/fix/66412-part-8
refactor buildOptimisticWorkspaceChats to use currentUserAccountID and currentUserEmail from useOnyx
2 parents e19e2f0 + 211b47e commit 0f49da9

5 files changed

Lines changed: 170 additions & 10 deletions

File tree

src/libs/ReportUtils.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8578,17 +8578,24 @@ function shouldPinAdminRoomByDefault() {
85788578
return !isExpensifyTeam(deprecatedCurrentUserEmail);
85798579
}
85808580

8581-
function buildOptimisticWorkspaceChats(policyID: string, policyName: string, expenseReportId?: string): OptimisticWorkspaceChats {
8582-
const pendingChatMembers = getPendingChatMembers(deprecatedCurrentUserAccountID ? [deprecatedCurrentUserAccountID] : [], [], CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD);
8581+
function buildOptimisticWorkspaceChats(
8582+
policyID: string,
8583+
policyName: string,
8584+
currentUserAccountID: number | undefined,
8585+
currentUserEmail: string | undefined,
8586+
expenseReportId?: string,
8587+
): OptimisticWorkspaceChats {
8588+
const pendingChatMembers = getPendingChatMembers(currentUserAccountID ? [currentUserAccountID] : [], [], CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD);
85838589
const adminsChatData = {
85848590
...buildOptimisticChatReport({
8585-
participantList: deprecatedCurrentUserAccountID ? [deprecatedCurrentUserAccountID] : [],
8591+
participantList: currentUserAccountID ? [currentUserAccountID] : [],
85868592
reportName: CONST.REPORT.WORKSPACE_CHAT_ROOMS.ADMINS,
85878593
chatType: CONST.REPORT.CHAT_TYPE.POLICY_ADMINS,
85888594
policyID,
85898595
ownerAccountID: CONST.POLICY.OWNER_ACCOUNT_ID_FAKE,
85908596
oldPolicyName: policyName,
85918597
isPinned: shouldPinAdminRoomByDefault(),
8598+
currentUserAccountID,
85928599
}),
85938600
};
85948601
const adminsChatReportID = adminsChatData.reportID;
@@ -8598,18 +8605,19 @@ function buildOptimisticWorkspaceChats(policyID: string, policyName: string, exp
85988605
};
85998606

86008607
const expenseChatData = buildOptimisticChatReport({
8601-
participantList: deprecatedCurrentUserAccountID ? [deprecatedCurrentUserAccountID] : [],
8608+
participantList: currentUserAccountID ? [currentUserAccountID] : [],
86028609
reportName: '',
86038610
chatType: CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT,
86048611
policyID,
8605-
ownerAccountID: deprecatedCurrentUserAccountID,
8612+
ownerAccountID: currentUserAccountID,
86068613
isOwnPolicyExpenseChat: true,
86078614
oldPolicyName: policyName,
86088615
optimisticReportID: expenseReportId,
8616+
currentUserAccountID,
86098617
});
86108618

86118619
const expenseChatReportID = expenseChatData.reportID;
8612-
const expenseReportCreatedAction = buildOptimisticCreatedReportAction(deprecatedCurrentUserEmail ?? '');
8620+
const expenseReportCreatedAction = buildOptimisticCreatedReportAction(currentUserEmail ?? '');
86138621
const expenseReportActionData = {
86148622
[expenseReportCreatedAction.reportActionID]: expenseReportCreatedAction,
86158623
};

src/libs/actions/Policy/Policy.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ type CreateWorkspaceDataOptions = Omit<BuildPolicyDataOptions, 'isSelfTourViewed
222222

223223
type DuplicatePolicyDataOptions = {
224224
currentUserAccountID: number;
225+
currentUserEmail: string | undefined;
225226
policyName: string;
226227
policyID?: string;
227228
targetPolicyID?: string;
@@ -2451,7 +2452,7 @@ function buildPolicyData(options: BuildPolicyDataOptions): OnyxData<BuildPolicyD
24512452
expenseReportActionData,
24522453
expenseCreatedReportActionID,
24532454
pendingChatMembers,
2454-
} = ReportUtils.buildOptimisticWorkspaceChats(policyID, workspaceName, expenseReportId);
2455+
} = ReportUtils.buildOptimisticWorkspaceChats(policyID, workspaceName, currentUserAccountIDParam, currentUserEmailParam, expenseReportId);
24552456

24562457
const optimisticCategoriesData = buildOptimisticPolicyCategories(policyID, Object.values(CONST.POLICY.DEFAULT_CATEGORIES));
24572458
const optimisticMccGroupData = buildOptimisticMccGroup();
@@ -3000,6 +3001,8 @@ function createDraftWorkspace(
30003001
const {expenseChatData, adminsChatReportID, adminsCreatedReportActionID, expenseChatReportID, expenseCreatedReportActionID} = ReportUtils.buildOptimisticWorkspaceChats(
30013002
policyID,
30023003
workspaceName,
3004+
currentUserAccountID,
3005+
currentUserEmail,
30033006
);
30043007

30053008
const shouldEnableWorkflowsByDefault =
@@ -3110,7 +3113,18 @@ function createDraftWorkspace(
31103113
}
31113114

31123115
function buildDuplicatePolicyData(policy: Policy, options: DuplicatePolicyDataOptions) {
3113-
const {policyName = '', policyID = generatePolicyID(), file, welcomeNote, parts, targetPolicyID = generatePolicyID(), policyCategories, localCurrency, currentUserAccountID} = options;
3116+
const {
3117+
policyName = '',
3118+
policyID = generatePolicyID(),
3119+
file,
3120+
welcomeNote,
3121+
parts,
3122+
targetPolicyID = generatePolicyID(),
3123+
policyCategories,
3124+
localCurrency,
3125+
currentUserAccountID,
3126+
currentUserEmail,
3127+
} = options;
31143128

31153129
const {
31163130
adminsChatReportID,
@@ -3122,7 +3136,7 @@ function buildDuplicatePolicyData(policy: Policy, options: DuplicatePolicyDataOp
31223136
expenseReportActionData,
31233137
expenseCreatedReportActionID,
31243138
pendingChatMembers,
3125-
} = ReportUtils.buildOptimisticWorkspaceChats(targetPolicyID, policyName);
3139+
} = ReportUtils.buildOptimisticWorkspaceChats(targetPolicyID, policyName, currentUserAccountID, currentUserEmail);
31263140
const isMemberOptionSelected = parts?.people;
31273141
const isReportsOptionSelected = parts?.reports;
31283142
const isConnectionsOptionSelected = parts?.connections;
@@ -3978,7 +3992,7 @@ function createWorkspaceFromIOUPayment(
39783992
expenseReportActionData: workspaceChatReportActionData,
39793993
expenseCreatedReportActionID: workspaceChatCreatedReportActionID,
39803994
pendingChatMembers,
3981-
} = ReportUtils.buildOptimisticWorkspaceChats(policyID, workspaceName);
3995+
} = ReportUtils.buildOptimisticWorkspaceChats(policyID, workspaceName, currentUserAccountID, currentUserEmail);
39823996

39833997
if (!employeeAccountID || !oldPersonalPolicyID) {
39843998
return;

src/pages/workspace/duplicate/WorkspaceDuplicateSelectFeaturesForm.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ function WorkspaceDuplicateSelectFeaturesForm({policyID}: WorkspaceDuplicateForm
222222

223223
duplicateWorkspaceAction(policy, {
224224
currentUserAccountID: currentUserPersonalDetails.accountID,
225+
currentUserEmail: currentUserPersonalDetails.email,
225226
policyName: duplicateWorkspace.name,
226227
policyID: policy.id,
227228
targetPolicyID: duplicateWorkspace.policyID,
@@ -257,6 +258,7 @@ function WorkspaceDuplicateSelectFeaturesForm({policyID}: WorkspaceDuplicateForm
257258
translate,
258259
duplicatedWorkspaceAvatar,
259260
currentUserPersonalDetails.accountID,
261+
currentUserPersonalDetails.email,
260262
currentUserPersonalDetails?.localCurrencyCode,
261263
]);
262264

tests/actions/PolicyTest.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ describe('actions/Policy', () => {
283283

284284
const options = {
285285
currentUserAccountID: ESH_ACCOUNT_ID,
286+
currentUserEmail: ESH_EMAIL,
286287
policyName: POLICY_NAME,
287288
policyID: fakePolicy.id,
288289
targetPolicyID: policyID,
@@ -476,6 +477,7 @@ describe('actions/Policy', () => {
476477

477478
const options = {
478479
currentUserAccountID: ESH_ACCOUNT_ID,
480+
currentUserEmail: ESH_EMAIL,
479481
policyName: 'Distance Disabled Workspace',
480482
policyID: fakePolicy.id,
481483
targetPolicyID: policyID,
@@ -534,6 +536,7 @@ describe('actions/Policy', () => {
534536

535537
const options = {
536538
currentUserAccountID: ESH_ACCOUNT_ID,
539+
currentUserEmail: ESH_EMAIL,
537540
policyName: 'Overview Travel CodingRules Workspace',
538541
policyID: fakePolicy.id,
539542
targetPolicyID: policyID,
@@ -606,6 +609,7 @@ describe('actions/Policy', () => {
606609
const policyID = Policy.generatePolicyID();
607610
const options = {
608611
currentUserAccountID: ESH_ACCOUNT_ID,
612+
currentUserEmail: ESH_EMAIL,
609613
policyName: 'Workspace With Members',
610614
policyID: fakePolicy.id,
611615
targetPolicyID: policyID,
@@ -658,6 +662,7 @@ describe('actions/Policy', () => {
658662
const file = {uri: 'file://tmp/avatar.png', name: 'avatar.png', type: 'image/png'} as File;
659663
const options = {
660664
currentUserAccountID: ESH_ACCOUNT_ID,
665+
currentUserEmail: ESH_EMAIL,
661666
policyName: 'Workspace With Avatar',
662667
policyID: fakePolicy.id,
663668
targetPolicyID: policyID,
@@ -697,6 +702,73 @@ describe('actions/Policy', () => {
697702
expect(policy?.originalFileName).toBe(file.name);
698703
});
699704

705+
it('duplicate workspace propagates the caller currentUserEmail to the expense chat CREATED report action message', async () => {
706+
await Onyx.set(ONYXKEYS.SESSION, {email: ESH_EMAIL, accountID: ESH_ACCOUNT_ID});
707+
const fakePolicy = createRandomPolicy(18, CONST.POLICY.TYPE.TEAM);
708+
await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${fakePolicy.id}`, fakePolicy);
709+
await waitForBatchedUpdates();
710+
711+
const policyID = Policy.generatePolicyID();
712+
const callerEmail = 'explicit-caller@expensifail.com';
713+
const options = {
714+
currentUserAccountID: ESH_ACCOUNT_ID,
715+
currentUserEmail: callerEmail,
716+
policyName: 'Workspace Propagating Caller Email',
717+
policyID: fakePolicy.id,
718+
targetPolicyID: policyID,
719+
welcomeNote: 'Join my policy',
720+
parts: {
721+
people: false,
722+
reports: false,
723+
connections: false,
724+
categories: false,
725+
tags: false,
726+
taxes: false,
727+
perDiem: false,
728+
reimbursements: false,
729+
expenses: false,
730+
distance: false,
731+
invoices: false,
732+
exportLayouts: false,
733+
},
734+
localCurrency: 'USD',
735+
};
736+
737+
Policy.duplicateWorkspace(fakePolicy, options);
738+
await waitForBatchedUpdates();
739+
740+
const allReports: OnyxCollection<Report> = await new Promise((resolve) => {
741+
const connection = Onyx.connect({
742+
key: ONYXKEYS.COLLECTION.REPORT,
743+
waitForCollectionCallback: true,
744+
callback: (reports) => {
745+
Onyx.disconnect(connection);
746+
resolve(reports);
747+
},
748+
});
749+
});
750+
751+
const expenseChat = Object.values(allReports ?? {}).find((report) => report?.policyID === policyID && report?.chatType === CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT);
752+
expect(expenseChat).toBeTruthy();
753+
754+
const reportActions: OnyxCollection<ReportActions> = await new Promise((resolve) => {
755+
const connection = Onyx.connect({
756+
key: ONYXKEYS.COLLECTION.REPORT_ACTIONS,
757+
waitForCollectionCallback: true,
758+
callback: (actions) => {
759+
Onyx.disconnect(connection);
760+
resolve(actions);
761+
},
762+
});
763+
});
764+
765+
const expenseChatActions: ReportAction[] = Object.values(reportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseChat?.reportID}`] ?? {});
766+
const createdAction = expenseChatActions.find((action) => action.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED);
767+
expect(createdAction).toBeTruthy();
768+
const messages = Array.isArray(createdAction?.message) ? createdAction?.message : [];
769+
expect(messages?.at(0)?.text).toBe(callerEmail);
770+
});
771+
700772
it('creates a new workspace with BASIC approval mode if the introSelected is MANAGE_TEAM', async () => {
701773
const policyID = Policy.generatePolicyID();
702774
// When a new workspace is created with introSelected set to MANAGE_TEAM

tests/unit/ReportUtilsTest.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import {
4747
buildOptimisticInvoiceReport,
4848
buildOptimisticIOUReportAction,
4949
buildOptimisticReportPreview,
50+
buildOptimisticWorkspaceChats,
5051
buildParticipantsFromAccountIDs,
5152
buildTransactionThread,
5253
canAddTransaction,
@@ -7079,6 +7080,69 @@ describe('ReportUtils', () => {
70797080
});
70807081
});
70817082

7083+
describe('buildOptimisticWorkspaceChats', () => {
7084+
const policyID = 'policy-workspace-chats-1';
7085+
const policyName = 'Workspace Chats Policy';
7086+
7087+
it('should build #admins and expense chats using the explicit currentUserAccountID for participants and pending members', () => {
7088+
const explicitCurrentUser = 777;
7089+
const explicitCurrentUserEmail = 'owner@expensifail.com';
7090+
const result = buildOptimisticWorkspaceChats(policyID, policyName, explicitCurrentUser, explicitCurrentUserEmail);
7091+
7092+
expect(result.adminsChatData.chatType).toBe(CONST.REPORT.CHAT_TYPE.POLICY_ADMINS);
7093+
expect(result.adminsChatData.policyID).toBe(policyID);
7094+
expect(result.adminsChatData.participants).toBeDefined();
7095+
expect(Object.keys(result.adminsChatData.participants ?? {}).map(Number)).toEqual([explicitCurrentUser]);
7096+
7097+
expect(result.expenseChatData.chatType).toBe(CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT);
7098+
expect(result.expenseChatData.policyID).toBe(policyID);
7099+
expect(result.expenseChatData.ownerAccountID).toBe(explicitCurrentUser);
7100+
expect(result.expenseChatData.isOwnPolicyExpenseChat).toBe(true);
7101+
expect(Object.keys(result.expenseChatData.participants ?? {}).map(Number)).toEqual([explicitCurrentUser]);
7102+
7103+
expect(result.pendingChatMembers).toHaveLength(1);
7104+
expect(result.pendingChatMembers.at(0)?.accountID).toBe(String(explicitCurrentUser));
7105+
expect(result.pendingChatMembers.at(0)?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD);
7106+
});
7107+
7108+
it('should use the provided currentUserEmail as the text of the expense CREATED report action', () => {
7109+
const explicitCurrentUser = 888;
7110+
const explicitCurrentUserEmail = 'duplicate-user@expensifail.com';
7111+
const result = buildOptimisticWorkspaceChats(policyID, policyName, explicitCurrentUser, explicitCurrentUserEmail);
7112+
7113+
const createdAction = result.expenseReportActionData[result.expenseCreatedReportActionID];
7114+
expect(createdAction).toBeDefined();
7115+
expect(createdAction.actionName).toBe(CONST.REPORT.ACTIONS.TYPE.CREATED);
7116+
const messages = Array.isArray(createdAction.message) ? createdAction.message : [];
7117+
expect(messages.at(0)?.text).toBe(explicitCurrentUserEmail);
7118+
});
7119+
7120+
it('should default the expense CREATED report action text to an empty string when currentUserEmail is undefined', () => {
7121+
const result = buildOptimisticWorkspaceChats(policyID, policyName, 100, undefined);
7122+
7123+
const createdAction = result.expenseReportActionData[result.expenseCreatedReportActionID];
7124+
const messages = Array.isArray(createdAction.message) ? createdAction.message : [];
7125+
expect(messages.at(0)?.text).toBe('');
7126+
});
7127+
7128+
it('should produce no participants or pending members when currentUserAccountID is undefined', () => {
7129+
const result = buildOptimisticWorkspaceChats(policyID, policyName, undefined, 'anon@expensifail.com');
7130+
7131+
expect(Object.keys(result.adminsChatData.participants ?? {})).toHaveLength(0);
7132+
expect(Object.keys(result.expenseChatData.participants ?? {})).toHaveLength(0);
7133+
expect(result.expenseChatData.ownerAccountID).toBe(CONST.REPORT.OWNER_ACCOUNT_ID_FAKE);
7134+
expect(result.pendingChatMembers).toHaveLength(0);
7135+
});
7136+
7137+
it('should use the provided expenseReportId as the expense chat reportID', () => {
7138+
const providedExpenseReportID = 'expense-report-123';
7139+
const result = buildOptimisticWorkspaceChats(policyID, policyName, 100, 'user@expensifail.com', providedExpenseReportID);
7140+
7141+
expect(result.expenseChatReportID).toBe(providedExpenseReportID);
7142+
expect(result.expenseChatData.reportID).toBe(providedExpenseReportID);
7143+
});
7144+
});
7145+
70827146
describe('getWorkspaceNameUpdatedMessage', () => {
70837147
it('return the encoded workspace name updated message', () => {
70847148
const action = {

0 commit comments

Comments
 (0)