Repository navigation
feat: presence sync #7392
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
feat: presence sync #7392
Changes from 109 commits
Commits
Show all changes
111 commits
Select commit
Hold shift + click to select a range
a722c69
Initial commit
Rohit3523 06d87c9
action: organized translations
Rohit3523 f2a4f52
Merge branch 'develop' into feat/presence-sync
Rohit3523 21a3b24
More translation
Rohit3523 939a20c
another one ;-;
Rohit3523 5e99b20
more changes
Rohit3523 8cf4f31
more lint fix
Rohit3523 eb726ff
action: organized translations
Rohit3523 7bab135
rerun ci
Rohit3523 61c6a6f
revert
Rohit3523 9833cc5
fix status update in room action and user info
Rohit3523 a39a305
added story...
Rohit3523 fb840e2
update style
Rohit3523 39307c4
remove status icon from avatar
Rohit3523 4d7a42b
added default presence in header and other screen
Rohit3523 27b711e
Merge branch 'develop' into feat/presence-sync
Rohit3523 857ebe6
lint fix
Rohit3523 4ff2cf4
using dayjs instead of date...
Rohit3523 20fa898
i18n fix
Rohit3523 231d6a4
makinf code rabbit happy
Rohit3523 397de8c
translation fix for Until
Rohit3523 babc5a9
changes
Rohit3523 ae442af
revert logic
Rohit3523 e0c2318
minor change
Rohit3523 6c4f06a
Merge branch 'develop' into feat/presence-sync
Rohit3523 1fbd54d
Remove view because it was not in use
Rohit3523 05c876a
Merge branch 'develop' into feat/presence-sync
Rohit3523 20001d5
lint fix
Rohit3523 1a56516
improve style and change date format
Rohit3523 5723523
user can't set away status manually and display only when user is away
Rohit3523 9837a00
Merge branch 'feat/presence-sync' of https://github.com/RocketChat/Ro…
Rohit3523 c656077
Merge branch 'develop' into feat/presence-sync
Rohit3523 75bb2a4
Improve accessibility label
Rohit3523 382e6e5
Merge branch 'develop' into feat/presence-sync
Rohit3523 4b56474
lint fix
Rohit3523 2e93202
Merge branch 'feat/presence-sync' of https://github.com/RocketChat/Ro…
Rohit3523 26ee9b8
snapshot update
Rohit3523 786c6cf
more improvements
Rohit3523 4d8286b
ui improve
Rohit3523 ec25a8a
show expire time in edit status
Rohit3523 c4994ef
story fix
Rohit3523 0a4f77c
lint fix
Rohit3523 e3a13b6
fix subtitle accessibility issue
Rohit3523 fa3c8ef
revert logic
Rohit3523 b6e0b4d
ratelimit toast was showing no text
Rohit3523 77a2956
Merge branch 'develop' into feat/presence-sync
Rohit3523 de8ee2e
use rest api instead of methodcall for set status
Rohit3523 fddd071
Added api return type
Rohit3523 f3343f9
fix type...
Rohit3523 78ae8e3
fake time in jest
Rohit3523 97520c9
added componentDidUpdate to make the logic simple...
Rohit3523 126ac6f
Merge branch 'develop' into feat/presence-sync
Rohit3523 175f926
member is no longer slate...
Rohit3523 b00209b
story fix
Rohit3523 2e8f500
remove padding from story, seems unrelated
Rohit3523 99dbded
Merge branch 'develop' into feat/presence-sync
Rohit3523 a124e4e
lint fix
Rohit3523 3cfb867
fix lint
Rohit3523 bfd2efb
fix fake time
Rohit3523 e465f5d
lint fix
Rohit3523 b85607d
improve
Rohit3523 775a0f4
Using ejson in normalizeStatusExpiresAt
Rohit3523 e53a879
statusview changes
Rohit3523 ac2bef8
clearafter picker changes
Rohit3523 0007eda
stop rerendering but with a weird logic...
Rohit3523 f556439
another optimisation
Rohit3523 6cc87b9
Improve...
Rohit3523 4b27d70
Story for roominfoviewavatar
Rohit3523 083dd60
Added align item to make it look good i mean the edit button
Rohit3523 b0a1a44
added line height
Rohit3523 d362cfb
combined status row...
Rohit3523 00f1dab
improve ts
Rohit3523 26dec67
lint fix
Rohit3523 77c30ba
improve
Rohit3523 8cc6d0a
lint fix
Rohit3523 be094b3
until i18n and formatStatusExpiry fix
Rohit3523 d063038
remove duplicate status from room header accessibility label
Rohit3523 4df50f9
lint fix
Rohit3523 e669b23
story improve
Rohit3523 d9f4a68
added normalizeStatusExpiresAt in rest as well
Rohit3523 d1b228c
Added version comment in user.setStatus
Rohit3523 9a0f189
remove duplicate story
Rohit3523 9cb76ec
lint fix
Rohit3523 cf101d6
improve inline style
Rohit3523 8c40847
Merge branch 'develop' into feat/presence-sync
Rohit3523 0e6ead5
remove testid
Rohit3523 ac5e8ac
Merge branch 'feat/presence-sync' of https://github.com/RocketChat/Ro…
Rohit3523 170b971
added undefined check in formatStatusExpiry
Rohit3523 9ba18d6
improve statusrow component conditional rendering
Rohit3523 6695653
added story for status row
Rohit3523 34637a8
remove duplicate normalizeStatusExpiresAt
Rohit3523 1e1c6bf
added shallowEqual in activeUserStatus
Rohit3523 dcab767
passing loggedUserId in getUidDirectMessage
Rohit3523 537de0e
added unit test
Rohit3523 2829e2f
lint fix
Rohit3523 abb107a
lint fix
Rohit3523 3490c4f
remove conditional formatStatusExpiry
Rohit3523 44b8479
memo formatStatusExpiry
Rohit3523 6ba39a1
Merge branch 'develop' into feat/presence-sync
Rohit3523 09feeab
Improve
Rohit3523 50feae4
Merge branch 'develop' into feat/presence-sync
Rohit3523 eb1970e
Move clearafter picker to seperate component
Rohit3523 9aa4116
revert unwanted change
Rohit3523 f130591
more changes
Rohit3523 390a832
added use meo
Rohit3523 6f02c89
more test
Rohit3523 db923b9
more test
Rohit3523 e72e798
lint fix
Rohit3523 314c42d
Merge branch 'develop' into feat/presence-sync
Rohit3523 8cd4269
wrap onConfirm in act
Rohit3523 09b25cb
passing fake time in unit test
Rohit3523 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,7 @@ | ||
| import { generateSnapshots } from '../../../.rnstorybook/generateSnapshots'; | ||
| import * as stories from './RoomHeader.stories'; | ||
|
|
||
| jest.useFakeTimers(); | ||
| jest.setSystemTime(new Date('2026-06-15T12:00:00.000Z')); | ||
|
|
||
| generateSnapshots(stories); |
|
diegolmello marked this conversation as resolved.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,167 @@ | ||
| import { type ReactNode } from 'react'; | ||
| import { render } from '@testing-library/react-native'; | ||
| import { Provider } from 'react-redux'; | ||
|
|
||
| import { mockedStore } from '../../reducers/mockedStore'; | ||
| import { setActiveUsers } from '../../actions/activeUsers'; | ||
| import { connectSuccess, connectRequest, disconnect } from '../../actions/connect'; | ||
| import { initStore } from '../../lib/store/auxStore'; | ||
| import { selectServerSuccess } from '../../actions/server'; | ||
| import RoomHeaderContainer from './index'; | ||
|
|
||
| const mockChild = jest.fn<any, [Record<string, unknown>]>(() => null); | ||
| jest.mock('./RoomHeader', () => ({ | ||
| __esModule: true, | ||
| default: (props: Record<string, unknown>) => { | ||
| mockChild(props); | ||
| return null; | ||
| } | ||
| })); | ||
|
|
||
| const Wrapper = ({ children }: { children: ReactNode }) => <Provider store={mockedStore}>{children}</Provider>; | ||
|
|
||
| const defaultProps = { | ||
| title: 'John Doe', | ||
| type: 'd', | ||
| roomUserId: 'user-123', | ||
| onPress: jest.fn() | ||
| }; | ||
|
|
||
| const renderContainer = (props: Record<string, unknown> = {}) => | ||
| render(<RoomHeaderContainer {...defaultProps} {...props} />, { wrapper: Wrapper }); | ||
|
|
||
| describe('RoomHeaderContainer', () => { | ||
| beforeAll(() => { | ||
| initStore(mockedStore); | ||
| }); | ||
|
|
||
| beforeEach(() => { | ||
| jest.clearAllMocks(); | ||
| mockedStore.dispatch(disconnect()); | ||
| }); | ||
|
|
||
| const connect = () => { | ||
| mockedStore.dispatch(selectServerSuccess({ server: 'https://example.com', version: '6.0.0', name: 'Test' })); | ||
| mockedStore.dispatch(connectSuccess()); | ||
| }; | ||
|
|
||
| it('should pass subtitle as Connecting when meteor is connecting for non-DM room', () => { | ||
| mockedStore.dispatch(connectRequest()); | ||
| mockedStore.dispatch(selectServerSuccess({ server: 'https://example.com', version: '6.0.0', name: 'Test' })); | ||
|
|
||
| renderContainer({ type: 'c', roomUserId: undefined }); | ||
|
|
||
| const props = mockChild.mock.calls[0][0]; | ||
| expect(props.subtitle).toBe('Connecting...'); | ||
| }); | ||
|
|
||
| it('should pass subtitle as Waiting for network... when not connected for non-DM room', () => { | ||
| mockedStore.dispatch(selectServerSuccess({ server: 'https://example.com', version: '6.0.0', name: 'Test' })); | ||
|
|
||
| renderContainer({ type: 'c', roomUserId: undefined }); | ||
|
|
||
| const props = mockChild.mock.calls[0][0]; | ||
| expect(props.subtitle).toBe('Waiting for network...'); | ||
| }); | ||
|
|
||
| it('should pass presence status for DM room when connected and activeUser exists', () => { | ||
| connect(); | ||
| mockedStore.dispatch( | ||
| setActiveUsers({ 'user-123': { status: 'online', statusText: 'Working from home', statusExpiresAt: undefined } }) | ||
| ); | ||
|
|
||
| renderContainer(); | ||
|
|
||
| const props = mockChild.mock.calls[0][0]; | ||
| expect(props.subtitle).toBe('Working from home'); | ||
| expect(props.type).toBe('d'); | ||
| }); | ||
|
|
||
| it('should pass statusExpiresAt for DM room when activeUser has it', () => { | ||
| connect(); | ||
| mockedStore.dispatch( | ||
| setActiveUsers({ | ||
| 'user-123': { status: 'away', statusText: 'In a meeting', statusExpiresAt: '2026-06-20T13:00:00.000Z' } | ||
| }) | ||
| ); | ||
|
|
||
| renderContainer(); | ||
|
|
||
| const props = mockChild.mock.calls[0][0]; | ||
| expect(props.subtitle).toBe('In a meeting'); | ||
| expect(props.statusExpiresAt).toBe('2026-06-20T13:00:00.000Z'); | ||
| }); | ||
|
|
||
| it('should use presence label when statusText is empty', () => { | ||
| connect(); | ||
| mockedStore.dispatch(setActiveUsers({ 'user-123': { status: 'busy', statusText: '', statusExpiresAt: undefined } })); | ||
|
|
||
| renderContainer(); | ||
|
|
||
| const props = mockChild.mock.calls[0][0]; | ||
| expect(props.subtitle).toBe('Busy'); | ||
| }); | ||
|
|
||
| it('should not pass statusExpiresAt for non-DM room', () => { | ||
| connect(); | ||
| mockedStore.dispatch( | ||
| setActiveUsers({ 'user-123': { status: 'away', statusText: 'Away', statusExpiresAt: '2026-06-20T13:00:00.000Z' } }) | ||
| ); | ||
|
|
||
| renderContainer({ type: 'c', roomUserId: undefined }); | ||
|
|
||
| const props = mockChild.mock.calls[0][0]; | ||
| expect(props.statusExpiresAt).toBeUndefined(); | ||
| }); | ||
|
|
||
| it('should pass subtitleProp when connected and no activeUser', () => { | ||
| connect(); | ||
|
|
||
| renderContainer({ subtitle: 'Custom subtitle', roomUserId: undefined, type: 'c' }); | ||
|
|
||
| const props = mockChild.mock.calls[0][0]; | ||
| expect(props.subtitle).toBe('Custom subtitle'); | ||
| }); | ||
|
|
||
| it('should pass roomUserId to RoomHeader', () => { | ||
| connect(); | ||
|
|
||
| renderContainer(); | ||
|
|
||
| const props = mockChild.mock.calls[0][0]; | ||
| expect(props.roomUserId).toBe('user-123'); | ||
| }); | ||
|
|
||
| it('should handle activeUser with offline status', () => { | ||
| connect(); | ||
| mockedStore.dispatch(setActiveUsers({ 'user-123': { status: 'offline', statusText: '', statusExpiresAt: undefined } })); | ||
|
|
||
| renderContainer(); | ||
|
|
||
| const props = mockChild.mock.calls[0][0]; | ||
| expect(props.subtitle).toBe('Offline'); | ||
| }); | ||
|
|
||
| it('should use statusText even when status is undefined', () => { | ||
| connect(); | ||
| mockedStore.dispatch( | ||
| setActiveUsers({ | ||
| 'user-123': { status: undefined, statusText: 'Custom text', statusExpiresAt: undefined } as any | ||
| }) | ||
| ); | ||
|
|
||
| renderContainer(); | ||
|
|
||
| const props = mockChild.mock.calls[0][0]; | ||
| expect(props.subtitle).toBe('Custom text'); | ||
| }); | ||
|
|
||
| it('should pass onPress to RoomHeader', () => { | ||
| connect(); | ||
|
|
||
| renderContainer(); | ||
|
|
||
| const props = mockChild.mock.calls[0][0]; | ||
| expect(props.onPress).toBe(defaultProps.onPress); | ||
| }); | ||
| }); |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't get the last 3. Can you explain?
IIRC Figma mentioned the clock only for some places (without the expiration).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have improved the story
Explanation
1-4 = normal status
5 = Passing future expire time to make sure clock icon is visible
6 = passing 1 hour future time to make sure clock icon is visible
7 = passing past time to make sure clock icon is not visible - added for edge case ;-;