Skip to content

Commit a27efe9

Browse files
fix: User custom status text being overwritten (RocketChat#36601)
Co-authored-by: Diego Sampaio <chinello@gmail.com>
1 parent fbf6c08 commit a27efe9

11 files changed

Lines changed: 81 additions & 17 deletions

File tree

.changeset/seven-donuts-confess.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@rocket.chat/meteor': patch
3+
---
4+
5+
Fixes an issue where user custom status text is being overwritten, causing it not being updated in real time

apps/meteor/app/api/server/v1/users.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1317,10 +1317,14 @@ API.v1.addRoute(
13171317
return API.v1.forbidden();
13181318
}
13191319

1320+
const { _id, username, roles, name } = user;
1321+
let { statusText } = user;
1322+
13201323
// TODO refactor to not update the user twice (one inside of `setStatusText` and then later just the status + statusDefault)
13211324

13221325
if (this.bodyParams.message || this.bodyParams.message === '') {
13231326
await setStatusText(user._id, this.bodyParams.message);
1327+
statusText = this.bodyParams.message;
13241328
}
13251329
if (this.bodyParams.status) {
13261330
const validStatus = ['online', 'away', 'offline', 'busy'];
@@ -1343,7 +1347,6 @@ API.v1.addRoute(
13431347
},
13441348
);
13451349

1346-
const { _id, username, statusText, roles, name } = user;
13471350
void api.broadcast('presence.status', {
13481351
user: { status, _id, username, statusText, roles, name },
13491352
previousStatus: user.status,

apps/meteor/client/sidebar/header/EditStatusModal.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import {
2121
import { useLocalStorage, useEffectEvent } from '@rocket.chat/fuselage-hooks';
2222
import { useToastMessageDispatch, useSetting, useTranslation, useEndpoint } from '@rocket.chat/ui-contexts';
2323
import type { ReactElement, ChangeEvent, ComponentProps, FormEvent } from 'react';
24-
import { useState, useCallback } from 'react';
24+
import { useState, useCallback, useId } from 'react';
2525

2626
import UserStatusMenu from '../../components/UserStatusMenu';
2727
import { USER_STATUS_TEXT_MAX_LENGTH } from '../../lib/constants';
@@ -39,6 +39,7 @@ const EditStatusModal = ({ onClose, userStatus, userStatusText }: EditStatusModa
3939
const initialStatusText = customStatus || userStatusText;
4040

4141
const t = useTranslation();
42+
const modalId = useId();
4243
const [statusText, setStatusText] = useState(initialStatusText);
4344
const [statusType, setStatusType] = useState(userStatus);
4445
const [statusTextError, setStatusTextError] = useState<string | undefined>();
@@ -71,6 +72,7 @@ const EditStatusModal = ({ onClose, userStatus, userStatusText }: EditStatusModa
7172

7273
return (
7374
<Modal
75+
aria-labelledby={`${modalId}-title`}
7476
wrapperFunction={(props: ComponentProps<typeof Box>) => (
7577
<Box
7678
is='form'
@@ -84,15 +86,17 @@ const EditStatusModal = ({ onClose, userStatus, userStatusText }: EditStatusModa
8486
>
8587
<ModalHeader>
8688
<ModalIcon name='info' />
87-
<ModalTitle>{t('Edit_Status')}</ModalTitle>
89+
<ModalTitle id={`${modalId}-title`}>{t('Edit_Status')}</ModalTitle>
8890
<ModalClose onClick={onClose} />
8991
</ModalHeader>
9092
<ModalContent fontScale='p2'>
9193
<FieldGroup>
9294
<Field>
93-
<FieldLabel>{t('StatusMessage')}</FieldLabel>
95+
<FieldLabel htmlFor={`${modalId}-status-message`}>{t('StatusMessage')}</FieldLabel>
9496
<FieldRow>
9597
<TextInput
98+
id={`${modalId}-status-message`}
99+
aria-label={t('StatusMessage')}
96100
error={statusTextError}
97101
disabled={!allowUserStatusMessageChange}
98102
flexGrow={1}

apps/meteor/client/sidebar/header/UserMenuHeader.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@ const UserMenuHeader = ({ user }: { user: IUser }) => {
2121
<Box mis={4} display='flex' overflow='hidden' flexDirection='column' fontScale='p2' mb='neg-x4' flexGrow={1} flexShrink={1}>
2222
<Box withTruncatedText w='full' display='flex' alignItems='center' flexDirection='row'>
2323
<Margins inline={4}>
24-
<UserStatus status={presenceDisabled ? 'disabled' : user.status} />
24+
<UserStatus
25+
role='status'
26+
aria-label={presenceDisabled ? t('user_status_disabled') : t(user?.status ?? 'offline')}
27+
status={presenceDisabled ? 'disabled' : user.status}
28+
/>
2529
<Box is='span' withTruncatedText display='inline-block' fontWeight='700'>
2630
{displayName}
2731
</Box>

apps/meteor/tests/e2e/e2e-encryption.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1056,7 +1056,7 @@ test.describe.serial('e2ee room setup', () => {
10561056
await expect(poHomeChannel.content.lastUserMessageBody).toHaveText('hello world');
10571057
await expect(poHomeChannel.content.lastUserMessage.locator('.rcx-icon--name-key')).toBeVisible();
10581058

1059-
await poHomeChannel.sidenav.userProfileMenu.click();
1059+
await poHomeChannel.sidenav.btnUserProfileMenu.click();
10601060
await poHomeChannel.sidenav.accountProfileOption.click();
10611061

10621062
await page.locator('role=navigation >> a:has-text("Security")').click();

apps/meteor/tests/e2e/page-objects/fragments/home-sidenav.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,18 @@ export class HomeSidenav {
4646
return this.page.locator('role=search >> role=searchbox').first();
4747
}
4848

49-
get userProfileMenu(): Locator {
49+
get btnUserProfileMenu(): Locator {
5050
return this.page.getByRole('button', { name: 'User menu', exact: true });
5151
}
5252

53+
get userProfileMenu(): Locator {
54+
return this.page.getByRole('menu', { name: 'User menu' });
55+
}
56+
57+
getUserProfileMenuOption(name: string): Locator {
58+
return this.userProfileMenu.getByRole('menuitemcheckbox', { name });
59+
}
60+
5361
get sidebarChannelsList(): Locator {
5462
return this.page.getByRole('list', { name: 'Channels' });
5563
}
@@ -152,12 +160,12 @@ export class HomeSidenav {
152160
}
153161

154162
async logout(): Promise<void> {
155-
await this.userProfileMenu.click();
163+
await this.btnUserProfileMenu.click();
156164
await this.page.locator('//*[contains(@class, "rcx-option__content") and contains(text(), "Logout")]').click();
157165
}
158166

159167
async switchStatus(status: 'offline' | 'online'): Promise<void> {
160-
await this.userProfileMenu.click();
168+
await this.btnUserProfileMenu.click();
161169
await this.page.locator(`role=menuitemcheckbox[name="${status}"]`).click();
162170
}
163171

apps/meteor/tests/e2e/page-objects/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,5 @@ export * from './omnichannel-settings';
1919
export * from './omnichannel-business-hours';
2020
export * from './omnichannel-tags';
2121
export * from './utils';
22+
export * from './modal';
2223
export * from './marketplace';

apps/meteor/tests/e2e/page-objects/modal.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ export class Modal {
77
this.page = page;
88
}
99

10+
getModalByName(name: string): Locator {
11+
return this.page.getByRole('dialog', { name });
12+
}
13+
1014
get textInput(): Locator {
1115
return this.page.locator('[name="modal_input"]');
1216
}

apps/meteor/tests/e2e/presence.spec.ts

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
import { DEFAULT_USER_CREDENTIALS, IS_EE } from './config/constants';
22
import { Users } from './fixtures/userStates';
3-
import { Registration } from './page-objects';
3+
import { Registration, HomeChannel } from './page-objects';
4+
import { Modal } from './page-objects/modal';
45
import { setSettingValueById } from './utils/setSettingValueById';
56
import { test, expect } from './utils/test';
67

78
test.describe.serial('Presence', () => {
89
let poRegistration: Registration;
10+
let poHomeChannel: HomeChannel;
911

1012
test.beforeEach(async ({ page }) => {
1113
poRegistration = new Registration(page);
14+
poHomeChannel = new HomeChannel(page);
1215

1316
await page.goto('/home');
1417
});
@@ -22,12 +25,44 @@ test.describe.serial('Presence', () => {
2225
});
2326

2427
test.describe('Login using default settings', () => {
25-
test('expect user to be online after log in', async ({ page }) => {
26-
await poRegistration.username.type('user1');
27-
await poRegistration.inputPassword.type(DEFAULT_USER_CREDENTIALS.password);
28+
test('should user be online after log in', async () => {
29+
await poRegistration.username.fill('user1');
30+
await poRegistration.inputPassword.fill(DEFAULT_USER_CREDENTIALS.password);
2831
await poRegistration.btnLogin.click();
2932

30-
await expect(page.getByRole('button', { name: 'User menu' }).locator('.rcx-status-bullet--online')).toBeVisible();
33+
await expect(poHomeChannel.sidenav.btnUserProfileMenu).toBeVisible();
34+
});
35+
});
36+
37+
test.describe('Custom status', () => {
38+
test.use({ storageState: Users.admin.state });
39+
40+
test('should user custom status be reactive', async ({ browser }) => {
41+
await test.step('user1 custom status should be empty', async () => {
42+
await poHomeChannel.sidenav.openChat('user1');
43+
44+
await expect(poHomeChannel.content.channelHeader).not.toContainText('new status');
45+
});
46+
47+
await test.step('update user1 custom status', async () => {
48+
const user1Page = await browser.newPage({ storageState: Users.user1.state });
49+
await user1Page.goto('/home');
50+
const user1Channel = new HomeChannel(user1Page);
51+
const user1Modal = new Modal(user1Page);
52+
53+
await user1Channel.sidenav.btnUserProfileMenu.click();
54+
await user1Channel.sidenav.getUserProfileMenuOption('Custom Status').click();
55+
await user1Modal.getModalByName('Edit Status').getByRole('textbox', { name: 'Status message' }).fill('new status');
56+
await user1Modal.getModalByName('Edit Status').getByRole('button', { name: 'Save' }).click();
57+
58+
await user1Page.close();
59+
});
60+
61+
await test.step('should user1 custom status be updated', async () => {
62+
await poHomeChannel.sidenav.openChat('user1');
63+
64+
await expect(poHomeChannel.content.channelHeader).toContainText('new status');
65+
});
3166
});
3267
});
3368

apps/meteor/tests/e2e/sidebar.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ test.describe.serial('sidebar', () => {
2323
});
2424

2525
test('should navigate on sidebar toolbar using arrow keys', async ({ page }) => {
26-
await poHomeChannel.sidenav.userProfileMenu.focus();
26+
await poHomeChannel.sidenav.btnUserProfileMenu.focus();
2727
await page.keyboard.press('Tab');
2828
await page.keyboard.press('ArrowRight');
2929

0 commit comments

Comments
 (0)