Skip to content

feat: Add user status on voice call widget#37217

Merged
kodiakhq[bot] merged 11 commits intodevelopfrom
feat/callStatus
Oct 28, 2025
Merged

feat: Add user status on voice call widget#37217
kodiakhq[bot] merged 11 commits intodevelopfrom
feat/callStatus

Conversation

@gabriellsh
Copy link
Member

@gabriellsh gabriellsh commented Oct 13, 2025

Proposed changes (including videos or screenshots)

Issue(s)

VGA-17

Steps to test or reproduce

Further comments

Summary by CodeRabbit

  • New Features
    • Added presence indicator (status bullet) across the call UI: visible in the call widget, transfer modal, peer autocomplete suggestions, and peer info display so user availability is shown alongside avatars.
    • Stories and mocked preview updated to reflect the new status display.

@dionisio-bot
Copy link
Contributor

dionisio-bot bot commented Oct 13, 2025

Looks like this PR is not ready to merge, because of the following issues:

  • This PR is targeting the wrong base branch. It should target 7.13.0, but it targets 7.12.0

Please fix the issues and try again

If you have any trouble, please check the PR guidelines

@changeset-bot
Copy link

changeset-bot bot commented Oct 13, 2025

🦋 Changeset detected

Latest commit: b2eb827

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 41 packages
Name Type
@rocket.chat/ui-voip Minor
@rocket.chat/meteor Patch
@rocket.chat/core-typings Patch
@rocket.chat/rest-typings Patch
@rocket.chat/uikit-playground Patch
@rocket.chat/api-client Patch
@rocket.chat/apps Patch
@rocket.chat/core-services Patch
@rocket.chat/cron Patch
@rocket.chat/ddp-client Patch
@rocket.chat/freeswitch Patch
@rocket.chat/fuselage-ui-kit Patch
@rocket.chat/gazzodown Patch
@rocket.chat/http-router Patch
@rocket.chat/livechat Patch
@rocket.chat/model-typings Patch
@rocket.chat/ui-avatar Patch
@rocket.chat/ui-client Patch
@rocket.chat/ui-contexts Patch
@rocket.chat/web-ui-registration Patch
@rocket.chat/account-service Patch
@rocket.chat/authorization-service Patch
@rocket.chat/ddp-streamer Patch
@rocket.chat/omnichannel-transcript Patch
@rocket.chat/presence-service Patch
@rocket.chat/queue-worker Patch
@rocket.chat/stream-hub-service Patch
@rocket.chat/federation-matrix Patch
@rocket.chat/license Patch
@rocket.chat/media-calls Patch
@rocket.chat/omnichannel-services Patch
@rocket.chat/pdf-worker Patch
@rocket.chat/presence Patch
rocketchat-services Patch
@rocket.chat/models Patch
@rocket.chat/network-broker Patch
@rocket.chat/omni-core-ee Patch
@rocket.chat/mock-providers Patch
@rocket.chat/ui-video-conf Patch
@rocket.chat/instance-status Patch
@rocket.chat/omni-core Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 13, 2025

Walkthrough

Adds user presence (status) propagation and rendering across the VoIP peer selection flow: presence is fetched via a presence hook, added to peer/autocomplete payloads and context, and rendered as StatusBullet UI next to user names in autocomplete and peer info components.

Changes

Cohort / File(s) Summary
Changeset
.changeset/itchy-books-report.md
Adds a changeset entry documenting the minor UI enhancement for presence indicators in call widget and transfer modal.
Context / Types
packages/ui-voip/src/v2/MediaCallContext.ts
Adds optional status?: UserStatus to InternalPeerInfo (and therefore propagates to exported PeerInfo shape).
Provider Logic
packages/ui-voip/src/v2/MediaCallProvider.tsx, packages/ui-voip/src/v2/MockedMediaCallProvider.tsx
Augments autocomplete option items and mock initial peer with status (uses user.status and UserStatus.ONLINE in mock).
Session Hook
packages/ui-voip/src/v2/useMediaSession.ts
Integrates useUserPresence, expands reducer actions to include status_updated, and augments returned MediaSession.peerInfo with status.
Autocomplete UI
packages/ui-voip/src/v2/components/PeerAutocomplete.tsx
Adds status?: UserStatus to PeerAutocompleteOptions and renders a StatusBullet next to option labels.
Peer Info UI
packages/ui-voip/src/v2/components/PeerInfo/InternalUser.tsx, packages/ui-voip/src/v2/components/PeerInfo/PeerInfo.stories.tsx
Adds status?: UserStatus prop to InternalUser, renders StatusBullet inline with display name; story updated to pass UserStatus.ONLINE.

Sequence Diagram(s)

sequenceDiagram
    participant User as Caller UI
    participant Auto as PeerAutocomplete
    participant Provider as MediaCallProvider / Context
    participant Presence as useUserPresence
    participant UI as StatusBullet Renderer

    User->>Auto: Open/select peer
    Auto->>Provider: Request autocomplete options
    Provider->>Presence: Read presence for users
    Presence-->>Provider: Return statuses
    Provider-->>Auto: Return options including status
    Auto->>UI: Render option with StatusBullet(status)
    UI-->>User: Display presence indicator
    Note over User,Auto: Call/Transfer actions remain enabled (non-blocking)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Areas needing extra attention:
    • useMediaSession.ts: integration of useUserPresence, reducer action additions and how status is merged into peerInfo.
    • Type changes in MediaCallContext.ts to ensure no downstream type conflicts.
    • Rendering in PeerAutocomplete.tsx and InternalUser.tsx to confirm layout and accessibility (status bullet + label spacing).

Suggested reviewers

  • aleksandernsilva

Poem

🐰 A tiny status dot hops near the name,
Showing who’s ready, who’s away in frame.
Bullets blink online, offline, and away,
Calls and transfers go on — no delay. 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "feat: Add user status on voice call widget" accurately and concisely describes the primary change in the pull request. The changeset consistently adds user status (presence) information throughout the voice call widget components, including the call widget, transfer UI, and related data structures. The title is specific enough to convey the feature without being unnecessarily detailed, following conventional commit messaging practices.
Linked Issues Check ✅ Passed The pull request successfully addresses all functional requirements and acceptance criteria from VGA-17. The implementation fetches user presence via the useUserPresence hook integration in useMediaSession.ts, displays status in the call widget through InternalUser.tsx with a StatusBullet component, and displays status in the transfer/autocomplete UI through PeerAutocomplete.tsx with the same visual indicator. The changes propagate the status field through PeerInfo types across all necessary components, and the presence display is implemented as a passive visual indicator that does not block, disable, or interrupt the call or transfer workflow, meeting the "No Interruption to Flow" requirement.
Out of Scope Changes Check ✅ Passed All changes in the pull request are directly aligned with the VGA-17 objective of displaying recipient presence status in call and transfer UI. The modifications include UserStatus type imports, StatusBullet component usage, presence hook integration, PeerInfo type extensions to carry status, and updates to related components and mocks—all of which are essential to fulfilling the feature requirements. No refactoring, dependency updates, or tangential changes outside the scope of this feature are present.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/callStatus

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link

codecov bot commented Oct 13, 2025

Codecov Report

❌ Patch coverage is 25.00000% with 12 lines in your changes missing coverage. Please review.
✅ Project coverage is 65.34%. Comparing base (157c0d1) to head (b2eb827).

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop   #37217      +/-   ##
===========================================
- Coverage    67.79%   65.34%   -2.46%     
===========================================
  Files         3345     3045     -300     
  Lines       114470   109490    -4980     
  Branches     20716    19601    -1115     
===========================================
- Hits         77605    71545    -6060     
- Misses       34178    35714    +1536     
+ Partials      2687     2231     -456     
Flag Coverage Δ
e2e 46.63% <ø> (-10.85%) ⬇️
unit 71.86% <25.00%> (+0.03%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@gabriellsh gabriellsh marked this pull request as ready for review October 21, 2025 15:43
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
packages/ui-voip/src/v2/MockedMediaCallProvider.tsx (2)

8-8: Add status field to mock data for consistency.

The initial peerInfo includes status: UserStatus.ONLINE (line 25), but the myData array items don't include a status field. This creates an inconsistency where selecting different peers in the mock won't populate the status.

Apply this diff:

-const myData: any[] = Array.from({ length: 100 }, (_, i) => ({ value: `user-${i}`, label: `User ${i}`, identifier: `000${i}`, avatarUrl }));
+const myData: any[] = Array.from({ length: 100 }, (_, i) => ({ 
+	value: `user-${i}`, 
+	label: `User ${i}`, 
+	identifier: `000${i}`, 
+	avatarUrl,
+	status: UserStatus.ONLINE,
+}));

61-74: Include status in getPeerInfo return value.

The getPeerInfo function returns a PeerInfo object without the status field, which is inconsistent with the initial state (line 25) and the real implementation in MediaCallProvider.tsx.

Apply this diff:

 	const getPeerInfo = (id: string) => {
 		const peerInfo = myData.find((item) => item.value === id);
 		if (!peerInfo) {
 			return Promise.resolve(undefined);
 		}
 
 		return Promise.resolve({
 			displayName: peerInfo.label,
 			userId: peerInfo.value,
 			avatarUrl: peerInfo.avatarUrl,
 			username: peerInfo.identifier,
 			callerId: peerInfo.value,
+			status: peerInfo.status,
 		});
 	};
packages/ui-voip/src/v2/MediaCallContext.ts (1)

192-197: Remove unsafe type cast.

The cast as UserStatus at line 196 is unsafe if localInfo.status contains an invalid value. This cast will become unnecessary once PeerAutocompleteOptions.status is properly typed as UserStatus instead of string (as suggested in PeerAutocomplete.tsx).

After fixing the type in PeerAutocomplete.tsx, update this code:

 		onSelectPeer({
 			userId: localInfo.value,
 			displayName: localInfo.label,
 			avatarUrl: localInfo.avatarUrl,
-			status: localInfo.status as UserStatus,
+			status: localInfo.status,
 		});
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 0870d72 and 60e5b06.

⛔ Files ignored due to path filters (1)
  • packages/ui-voip/src/v2/__snapshots__/MediaCallWidget.spec.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (7)
  • .changeset/itchy-books-report.md (1 hunks)
  • packages/ui-voip/src/v2/MediaCallContext.ts (3 hunks)
  • packages/ui-voip/src/v2/MediaCallProvider.tsx (3 hunks)
  • packages/ui-voip/src/v2/MockedMediaCallProvider.tsx (2 hunks)
  • packages/ui-voip/src/v2/components/PeerAutocomplete.tsx (3 hunks)
  • packages/ui-voip/src/v2/components/PeerInfo/InternalUser.tsx (1 hunks)
  • packages/ui-voip/src/v2/components/PeerInfo/PeerInfo.stories.tsx (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
packages/ui-voip/src/v2/components/PeerInfo/InternalUser.tsx (1)
packages/ui-voip/src/v2/components/PeerInfo/PeerInfo.stories.tsx (1)
  • InternalUser (12-31)
packages/ui-voip/src/v2/MediaCallProvider.tsx (1)
packages/ui-contexts/src/index.ts (1)
  • useUserPresence (96-96)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: 🔨 Test Unit / Unit Tests
  • GitHub Check: 🔎 Code Check / TypeScript
  • GitHub Check: 🔎 Code Check / Code Lint
  • GitHub Check: 🔨 Test Storybook / Test Storybook
  • GitHub Check: 📦 Meteor Build - coverage
  • GitHub Check: CodeQL-Build
🔇 Additional comments (5)
packages/ui-voip/src/v2/MediaCallContext.ts (1)

15-15: LGTM!

The addition of status?: UserStatus to InternalPeerInfo properly extends the type to support presence status throughout the call flow.

.changeset/itchy-books-report.md (1)

1-5: LGTM!

The changeset properly documents the new presence indicator feature as a minor version bump.

packages/ui-voip/src/v2/components/PeerInfo/PeerInfo.stories.tsx (1)

1-1: LGTM!

The story properly demonstrates the new status prop with UserStatus.ONLINE, providing visual documentation of the presence indicator feature.

Also applies to: 17-17

packages/ui-voip/src/v2/components/PeerInfo/InternalUser.tsx (1)

1-2: LGTM!

The component properly integrates the status indicator:

  • Accepts status?: UserStatus in props
  • Conditionally renders StatusBullet when status is provided
  • Layout updated to display status inline with the display name using flex row
  • Appropriate spacing with mis={4} between the bullet and name

Also applies to: 6-6, 11-11, 16-19

packages/ui-voip/src/v2/MediaCallProvider.tsx (1)

221-221: The review comment is incorrect—the code is already type-safe.

The user.status value is already properly typed through the API response chain:

  1. The /v1/users.autocomplete endpoint response is typed via rest-typings as Required<Pick<IUser, '_id' | 'name' | 'username' | 'nickname' | 'status' | 'avatarETag'>>[]
  2. The IUser.status field is typed as UserStatus (the enum defined in packages/core-typings/src/UserStatus.ts)
  3. TypeScript enforces this type at compile time, so user.status is guaranteed to be a valid UserStatus enum value

No additional type guards or runtime validation are needed. The existing type definitions already ensure type safety.

Likely an incorrect or invalid review comment.

@gabriellsh gabriellsh added this to the 7.13.0 milestone Oct 23, 2025
cardoso
cardoso previously approved these changes Oct 24, 2025
@gabriellsh gabriellsh added the stat: QA assured Means it has been tested and approved by a company insider label Oct 27, 2025
@dionisio-bot dionisio-bot bot added the stat: ready to merge PR tested and approved waiting for merge label Oct 27, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
packages/ui-voip/src/v2/useMediaSession.ts (3)

1-3: Tidy imports after reducer cleanup

If you remove payload.status above, UserStatus becomes unused here. Drop it to satisfy linters.

-import { UserStatus } from '@rocket.chat/core-typings';
 import { MediaSignalingSession, CallState, CallRole } from '@rocket.chat/media-signaling';
-import { useUserAvatarPath, useUserPresence } from '@rocket.chat/ui-contexts';
+import { useUserAvatarPath, useUserPresence } from '@rocket.chat/ui-contexts';

303-308: Gate presence to user peers and avoid name shadowing

Pass userId separately, rename local var, and only inject status for user peers. Prevents accidental SIP presence and clarifies intent.

-  const status = useUserPresence(mediaSession.peerInfo && 'userId' in mediaSession.peerInfo ? mediaSession.peerInfo.userId : undefined);
-
-  const peerInfo = useMemo(() => {
-    return mediaSession.peerInfo ? { ...mediaSession.peerInfo, status: status?.status } : undefined;
-  }, [mediaSession.peerInfo, status]);
+  const userId = mediaSession.peerInfo && 'userId' in mediaSession.peerInfo ? mediaSession.peerInfo.userId : undefined;
+  const presence = useUserPresence(userId);
+
+  const peerInfo = useMemo(() => {
+    if (!mediaSession.peerInfo) {
+      return undefined;
+    }
+    if ('userId' in mediaSession.peerInfo) {
+      return { ...mediaSession.peerInfo, status: presence?.status };
+    }
+    return mediaSession.peerInfo;
+  }, [mediaSession.peerInfo, presence?.status]);

Please confirm that useUserPresence(undefined) is a no-op and does not return the current user’s presence.


311-314: Avoid broad 'as MediaSession' assertion

Let TS check the shape; assign to a typed const and return it.

-    ...mediaSession,
-    peerInfo,
-    ...cbs,
-  } as MediaSession;
+    ...mediaSession,
+    peerInfo,
+    ...cbs,
+  } as const satisfies MediaSession; // if TS 4.9+; otherwise:
+  // const result: MediaSession = { ...mediaSession, peerInfo, ...cbs };
+  // return result;

If your TS version < 4.9, use the commented variant with an explicit const result: MediaSession.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 60e5b06 and 6152acb.

⛔ Files ignored due to path filters (1)
  • packages/ui-voip/src/v2/__snapshots__/MediaCallWidget.spec.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (3)
  • packages/ui-voip/src/v2/MediaCallProvider.tsx (1 hunks)
  • packages/ui-voip/src/v2/components/PeerAutocomplete.tsx (3 hunks)
  • packages/ui-voip/src/v2/useMediaSession.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/ui-voip/src/v2/MediaCallProvider.tsx
  • packages/ui-voip/src/v2/components/PeerAutocomplete.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
packages/ui-voip/src/v2/useMediaSession.ts (2)
packages/ui-voip/src/v2/useMediaSessionInstance.ts (1)
  • SessionInfo (31-31)
packages/ui-contexts/src/index.ts (1)
  • useUserPresence (96-96)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: 📦 Build Packages
  • GitHub Check: CodeQL-Build
  • GitHub Check: CodeQL-Build

@kodiakhq kodiakhq bot merged commit 713ce92 into develop Oct 28, 2025
47 of 48 checks passed
@kodiakhq kodiakhq bot deleted the feat/callStatus branch October 28, 2025 19:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stat: QA assured Means it has been tested and approved by a company insider stat: ready to merge PR tested and approved waiting for merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants