-
Notifications
You must be signed in to change notification settings - Fork 13.7k
feat: presence sync engine UI #40469
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
Changes from all commits
Commits
Show all changes
48 commits
Select commit
Hold shift + click to select a range
af9639d
feat: status expiration backend and API
ricardogarim 265f543
fix: keep UserPresence type unchanged for backend PR
ricardogarim 95f1d2b
remove unused i18n keys
ricardogarim 6768bcb
update changeset and use test adminUsername helper
ricardogarim 173a068
feat: status expiration backend and API
ricardogarim 2691c3f
feat: presence sync engine UI
ricardogarim 4b0b818
render DM partner status only in RoomMemberStatus
ricardogarim cd53953
fix: lighten profile form divider color to stroke-extra-light
ricardogarim b1c3261
fix: move status dot selector to left of status text on profile form
ricardogarim d8f941c
fix: correct status defaults in edit custom status modal
ricardogarim 062c3d2
feat: show call-aware warning in edit custom status modal
ricardogarim 8844c0a
chore: remove unused status i18n keys
ricardogarim cdb4981
change addon to startAddon on presence dot
ricardogarim f65a4f4
fix: only show away in edit custom status modal when it is the default
ricardogarim d18800b
use isTruthy instead of Boolean in UserStatusText filter
ricardogarim 6e690dd
build UserStatusText tooltip lazily on hover
ricardogarim 703913e
refactor: memoize useStatusItems menu for stable reference
ricardogarim ef082fa
refactor: return stable handlers object from useUserStatusTooltip
ricardogarim b84daa5
align custom menu item presence dot
ricardogarim 8c8abcf
fix: XSS in sidebar message preview via unescaped sender name
ricardogarim 48fd39a
rename user status menu action "Custom Status" to "Custom..."
ricardogarim 1fa9f65
resolve userId once for sidebar RoomList instead of per-row
ricardogarim f903b2b
chore: replace `title` by `aria-label` in UserCard
dougfabris aa76ba8
chore: remove unnecessary `div` in UserStatusText
dougfabris f34a6b2
fix: UserStatusMenu size variant
dougfabris 2cca3bd
fix: remove unnecessary timeout and improve useUserStatusTooltip to h…
dougfabris c98bfae
chore: remove onChange validation mode from EditStatusModal
ricardogarim f33ace5
chore: move status expiration validation to field-level rules
ricardogarim 96d0936
chore: use fuselage-forms for EditStatusModal and AccountProfileForm …
ricardogarim ef5b848
chore: use date-fns isSameDay in useExpirationText
ricardogarim 61e32ad
fix: pass missing title arg to useUserStatusTooltip in RoomMembersItem
ricardogarim 0a3ce0b
fix: title shouldn't be required in useUserStatusTooltip
dougfabris 2c82883
chore: revamp EditStatusModal
dougfabris cbd9f9d
chore: remove unnecessary return types
dougfabris 7c3c466
chore: remove unnecessary style in Divider
dougfabris 657684b
chore: use i18n interpolation for expiration text
dougfabris 340d5ed
fix: show status label as fallback when custom status has no text
ricardogarim 85fe433
fix: prevent setting expiration on online status without message
ricardogarim 59828eb
fix: merge user initial status values
dougfabris 23d15f6
test: adjust to new disabled rules
ricardogarim fb88b13
feat: presence sync engine integrations (#40557)
ricardogarim 38f4456
chore: remove video conference presence integration
ricardogarim d998135
chore: presence sync engine findings (#41035)
ricardogarim 4a5573f
chore: show Outlook prefix for calendar busy status (#41053)
ricardogarim da92feb
fix: show reactive status text on user card and user info (#41052)
ricardogarim 5bea13b
fix: shared validateStatusExpiration for account profile and edit sta…
dougfabris a4a1071
test: use alert role for edit status modal error locators
ricardogarim dba082e
fix: show offline users' custom status text and expiration (#41087)
ricardogarim 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
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
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
16 changes: 16 additions & 0 deletions
16
apps/meteor/client/components/UserStatusText/ReactiveUserStatusText.tsx
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,16 @@ | ||
| import type { IUser } from '@rocket.chat/core-typings'; | ||
| import { useUserPresence } from '@rocket.chat/ui-contexts'; | ||
| import { memo } from 'react'; | ||
|
|
||
| import UserStatusText from './UserStatusText'; | ||
|
|
||
| type ReactiveUserStatusTextProps = { | ||
| uid: IUser['_id']; | ||
| }; | ||
|
|
||
| const ReactiveUserStatusText = ({ uid }: ReactiveUserStatusTextProps) => { | ||
| const presence = useUserPresence(uid); | ||
| return <UserStatusText status={presence?.status} statusText={presence?.statusText} statusExpiresAt={presence?.statusExpiresAt} />; | ||
| }; | ||
|
|
||
| export default memo(ReactiveUserStatusText); |
47 changes: 47 additions & 0 deletions
47
apps/meteor/client/components/UserStatusText/UserStatusText.tsx
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,47 @@ | ||
| import { UserStatus } from '@rocket.chat/core-typings'; | ||
| import { Box, Icon } from '@rocket.chat/fuselage'; | ||
| import { isTruthy } from '@rocket.chat/tools'; | ||
| import { useTranslation } from 'react-i18next'; | ||
|
|
||
| import { useExpirationText } from '../../hooks/useExpirationText'; | ||
| import MarkdownText from '../MarkdownText'; | ||
|
|
||
| const STATUS_LABEL_KEYS: Record<UserStatus, string> = { | ||
| [UserStatus.ONLINE]: 'Online', | ||
| [UserStatus.AWAY]: 'Away', | ||
| [UserStatus.BUSY]: 'Busy', | ||
| [UserStatus.OFFLINE]: 'Offline', | ||
| [UserStatus.DISABLED]: 'Disabled', | ||
| }; | ||
|
|
||
| type UserStatusTextProps = { | ||
| status?: UserStatus; | ||
| statusText?: string; | ||
| statusExpiresAt?: Date | string; | ||
| }; | ||
|
|
||
| const UserStatusText = ({ status, statusText, statusExpiresAt }: UserStatusTextProps) => { | ||
| const { t } = useTranslation(); | ||
| const expirationText = useExpirationText(statusExpiresAt); | ||
|
|
||
| const statusLabel = status ? t(STATUS_LABEL_KEYS[status] ?? STATUS_LABEL_KEYS[UserStatus.OFFLINE]) : undefined; | ||
| const headline = [statusLabel, statusText].filter(isTruthy).join(' - '); | ||
|
|
||
| if (!headline && !expirationText) { | ||
| return null; | ||
| } | ||
|
|
||
| return ( | ||
| <> | ||
| {headline && <MarkdownText content={headline} parseEmoji={true} variant='inline' />} | ||
| {expirationText && ( | ||
| <Box fontScale='c1' display='flex' alignItems='center'> | ||
| <Icon name='clock' size='x16' mie={4} /> | ||
| {expirationText} | ||
| </Box> | ||
| )} | ||
| </> | ||
| ); | ||
| }; | ||
|
|
||
| export default UserStatusText; |
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,2 @@ | ||
| export { default as UserStatusText } from './UserStatusText'; | ||
| export { default as ReactiveUserStatusText } from './ReactiveUserStatusText'; |
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,55 @@ | ||
| import { useLanguage } from '@rocket.chat/ui-contexts'; | ||
| import { isSameDay } from 'date-fns'; | ||
| import { useMemo } from 'react'; | ||
| import { useTranslation } from 'react-i18next'; | ||
|
|
||
| import { useFormatDate } from './useFormatDate'; | ||
| import { useFormatTime } from './useFormatTime'; | ||
|
|
||
| // Handles Date, ISO string, and EJSON { $date } (from DDP streamer which does raw JSON.parse without EJSON deserialization) | ||
| function parseExpiresAt(value?: unknown): Date | undefined { | ||
| if (!value) { | ||
| return undefined; | ||
| } | ||
|
|
||
| if (value instanceof Date) { | ||
| return Number.isNaN(value.getTime()) ? undefined : value; | ||
| } | ||
|
|
||
| if (typeof value === 'object' && '$date' in (value as Record<string, unknown>)) { | ||
| const date = new Date((value as { $date: number }).$date); | ||
| return Number.isNaN(date.getTime()) ? undefined : date; | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| if (typeof value === 'string') { | ||
| const date = new Date(value); | ||
| return Number.isNaN(date.getTime()) ? undefined : date; | ||
| } | ||
|
|
||
| return undefined; | ||
| } | ||
|
|
||
| export function useExpirationText(statusExpiresAt?: Date | string) { | ||
| const { t } = useTranslation(); | ||
| const language = useLanguage(); | ||
| const formatTime = useFormatTime(); | ||
| const formatDate = useFormatDate(); | ||
|
|
||
| return useMemo(() => { | ||
| const expiresAt = parseExpiresAt(statusExpiresAt); | ||
| if (!expiresAt || expiresAt.getTime() <= Date.now()) { | ||
| return undefined; | ||
| } | ||
|
|
||
| const now = new Date(); | ||
| if (isSameDay(expiresAt, now)) { | ||
| return t('Until_time', { time: formatTime(expiresAt) }); | ||
| } | ||
|
|
||
| if (expiresAt.getFullYear() === now.getFullYear()) { | ||
| return t('Until_date', { date: new Intl.DateTimeFormat(language, { month: 'long', day: 'numeric' }).format(expiresAt) }); | ||
| } | ||
|
|
||
| return t('Until_date', { date: formatDate(expiresAt) }); | ||
| }, [statusExpiresAt, t, language, formatTime, formatDate]); | ||
| } | ||
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,30 @@ | ||
| import { useTooltipClose, useTooltipOpen, useUserPresence } from '@rocket.chat/ui-contexts'; | ||
| import type { MouseEvent } from 'react'; | ||
| import { useCallback, useMemo } from 'react'; | ||
|
|
||
| import { UserStatusText } from '../components/UserStatusText'; | ||
|
|
||
| export function useUserStatusTooltip(uid: string | undefined, title?: string) { | ||
| const presence = useUserPresence(uid); | ||
|
|
||
| const openTooltip = useTooltipOpen(); | ||
| const closeTooltip = useTooltipClose(); | ||
|
|
||
| const onMouseEnter = useCallback( | ||
| (e: MouseEvent<HTMLElement>) => { | ||
| const target = e.currentTarget; | ||
|
|
||
| if (!uid) { | ||
| return openTooltip(title, target); | ||
| } | ||
|
|
||
| openTooltip( | ||
| <UserStatusText status={presence?.status} statusText={presence?.statusText} statusExpiresAt={presence?.statusExpiresAt} />, | ||
| target, | ||
| ); | ||
| }, | ||
| [uid, openTooltip, presence, title], | ||
| ); | ||
|
ricardogarim marked this conversation as resolved.
|
||
|
|
||
| return useMemo(() => ({ 'data-tooltip': '', onMouseEnter, 'onMouseLeave': closeTooltip }), [onMouseEnter, closeTooltip]); | ||
| } | ||
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.
Uh oh!
There was an error while loading. Please reload this page.