Skip to content

Commit 988a3f1

Browse files
authored
Show icon for spotlighted participants in participant list (#4040)
* Add spotlight icon to participant list on call composites * Change files * Duplicate change files for beta release
1 parent c2d1ec4 commit 988a3f1

13 files changed

Lines changed: 122 additions & 13 deletions

File tree

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"type": "prerelease",
3+
"area": "feature",
4+
"workstream": "Spotlight",
5+
"comment": "Add spotlight icon to participant list on call composites",
6+
"packageName": "@azure/communication-react",
7+
"email": "79475487+mgamis-msft@users.noreply.github.com",
8+
"dependentChangeType": "patch"
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"type": "prerelease",
3+
"area": "feature",
4+
"workstream": "Spotlight",
5+
"comment": "Add spotlight icon to participant list on call composites",
6+
"packageName": "@azure/communication-react",
7+
"email": "79475487+mgamis-msft@users.noreply.github.com",
8+
"dependentChangeType": "patch"
9+
}

packages/calling-component-bindings/src/participantListSelector.ts

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,18 @@ import { memoizedConvertToVideoTileReaction } from './utils/participantListSelec
2222
import { memoizedConvertAllremoteParticipantsBetaRelease } from './utils/participantListSelectorUtils';
2323
/* @conditional-compile-remove(reaction) */
2424
import { memoizedConvertAllremoteParticipantsBeta } from './utils/participantListSelectorUtils';
25+
/* @conditional-compile-remove(spotlight) */
26+
import { memoizedSpotlight } from './utils/participantListSelectorUtils';
2527
/* @conditional-compile-remove(raise-hand) */
2628
import { getLocalParticipantRaisedHand } from './baseSelectors';
2729
/* @conditional-compile-remove(reaction) */
2830
import { getLocalParticipantReactionState } from './baseSelectors';
31+
/* @conditional-compile-remove(spotlight) */
32+
import { getSpotlightedParticipants } from './baseSelectors';
2933
import { toFlatCommunicationIdentifier } from '@internal/acs-ui-common';
3034
import { getParticipantCount } from './baseSelectors';
3135
import { isMicrosoftTeamsAppIdentifier, isPhoneNumberIdentifier } from '@azure/communication-common';
32-
import { ParticipantRole } from '@azure/communication-calling';
36+
import { ParticipantRole, SpotlightedParticipant } from '@azure/communication-calling';
3337
/* @conditional-compile-remove(hide-attendee-name) */
3438
import { maskDisplayNameWithRole } from './utils/callUtils';
3539
import { getRemoteParticipantsExcludingConsumers } from './getRemoteParticipantsExcludingConsumers';
@@ -38,7 +42,8 @@ const convertRemoteParticipantsToParticipantListParticipants = (
3842
remoteParticipants: RemoteParticipantState[],
3943
localUserCanRemoveOthers: boolean,
4044
isHideAttendeeNamesEnabled?: boolean,
41-
localUserRole?: ParticipantRole
45+
localUserRole?: ParticipantRole,
46+
spotlightedParticipants?: SpotlightedParticipant[]
4247
): CallParticipantListParticipant[] => {
4348
const conversionCallback = (
4449
memoizeFn: (...args: any[]) => CallParticipantListParticipant
@@ -79,6 +84,11 @@ const convertRemoteParticipantsToParticipantListParticipants = (
7984
);
8085
/* @conditional-compile-remove(reaction) */
8186
const remoteParticipantReaction = memoizedConvertToVideoTileReaction(participant.reactionState);
87+
/* @conditional-compile-remove(spotlight) */
88+
const spotlight = memoizedSpotlight(
89+
spotlightedParticipants,
90+
toFlatCommunicationIdentifier(participant.identifier)
91+
);
8292
return memoizeFn(
8393
toFlatCommunicationIdentifier(participant.identifier),
8494
displayName,
@@ -90,7 +100,9 @@ const convertRemoteParticipantsToParticipantListParticipants = (
90100
participant.raisedHand,
91101
localUserCanRemoveOthers,
92102
/* @conditional-compile-remove(reaction) */
93-
remoteParticipantReaction
103+
remoteParticipantReaction,
104+
/* @conditional-compile-remove(spotlight) */
105+
spotlight
94106
);
95107
})
96108
.sort((a, b) => {
@@ -146,7 +158,9 @@ export const participantListSelector: ParticipantListSelector = createSelector(
146158
/* @conditional-compile-remove(hide-attendee-name) */
147159
isHideAttendeeNamesEnabled,
148160
/* @conditional-compile-remove(reaction) */
149-
getLocalParticipantReactionState
161+
getLocalParticipantReactionState,
162+
/* @conditional-compile-remove(spotlight) */
163+
getSpotlightedParticipants
150164
],
151165
(
152166
userId,
@@ -161,7 +175,9 @@ export const participantListSelector: ParticipantListSelector = createSelector(
161175
/* @conditional-compile-remove(hide-attendee-name) */
162176
isHideAttendeeNamesEnabled,
163177
/* @conditional-compile-remove(reaction) */
164-
localParticipantReactionState
178+
localParticipantReactionState,
179+
/* @conditional-compile-remove(spotlight) */
180+
spotlightedParticipants
165181
): {
166182
participants: CallParticipantListParticipant[];
167183
myUserId: string;
@@ -175,7 +191,9 @@ export const participantListSelector: ParticipantListSelector = createSelector(
175191
/* @conditional-compile-remove(hide-attendee-name) */
176192
isHideAttendeeNamesEnabled,
177193
/* @conditional-compile-remove(hide-attendee-name) */
178-
role
194+
role,
195+
/* @conditional-compile-remove(spotlight) */
196+
spotlightedParticipants
179197
)
180198
: [];
181199
/* @conditional-compile-remove(reaction) */
@@ -191,7 +209,9 @@ export const participantListSelector: ParticipantListSelector = createSelector(
191209
// Local participant can never remove themselves.
192210
isRemovable: false,
193211
/* @conditional-compile-remove(reaction) */
194-
reaction: localParticipantReaction
212+
reaction: localParticipantReaction,
213+
/* @conditional-compile-remove(spotlight) */
214+
isSpotlighted: memoizedSpotlight(spotlightedParticipants, userId)
195215
});
196216
/* @conditional-compile-remove(total-participant-count) */
197217
const totalParticipantCount = partitipantCount;

packages/calling-component-bindings/src/utils/participantListSelectorUtils.ts

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,15 @@
22
// Licensed under the MIT License.
33

44
import { RemoteParticipantState } from '@azure/communication-calling';
5+
/* @conditional-compile-remove(spotlight) */
6+
import { SpotlightedParticipant } from '@azure/communication-calling';
57
import { getIdentifierKind } from '@azure/communication-common';
68
import { fromFlatCommunicationIdentifier, memoizeFnAll } from '@internal/acs-ui-common';
9+
/* @conditional-compile-remove(spotlight) */
10+
import { toFlatCommunicationIdentifier } from '@internal/acs-ui-common';
711
import { CallParticipantListParticipant } from '@internal/react-components';
12+
/* @conditional-compile-remove(spotlight) */
13+
import { Spotlight } from '@internal/react-components';
814
/* @conditional-compile-remove(raise-hand) */
915
import { RaisedHandState } from '@internal/calling-stateful-client';
1016
/* @conditional-compile-remove(reaction) */
@@ -110,7 +116,8 @@ export const memoizedConvertAllremoteParticipantsBeta = memoizeFnAll(
110116
isSpeaking: boolean,
111117
raisedHand: RaisedHandState | undefined,
112118
localUserCanRemoveOthers: boolean,
113-
reaction: Reaction | undefined
119+
reaction: Reaction | undefined,
120+
isSpotlighted: Spotlight | undefined
114121
): CallParticipantListParticipant => {
115122
return convertRemoteParticipantToParticipantListParticipantBeta(
116123
userId,
@@ -121,7 +128,8 @@ export const memoizedConvertAllremoteParticipantsBeta = memoizeFnAll(
121128
isSpeaking,
122129
raisedHand,
123130
localUserCanRemoveOthers,
124-
reaction
131+
reaction,
132+
isSpotlighted
125133
);
126134
}
127135
);
@@ -141,6 +149,19 @@ export const memoizedConvertToVideoTileReaction = memoizeOne(
141149
}
142150
);
143151

152+
/* @conditional-compile-remove(reaction) */
153+
/**
154+
* @private
155+
*/
156+
export const memoizedSpotlight = memoizeOne(
157+
(spotlightedParticipants: SpotlightedParticipant[] | undefined, userId: string): Spotlight | undefined => {
158+
const spotlightOrder = spotlightedParticipants?.find(
159+
(spotlightedParticipant) => toFlatCommunicationIdentifier(spotlightedParticipant.identifier) === userId
160+
);
161+
return spotlightOrder ? { spotlightOrderPosition: spotlightOrder.order } : undefined;
162+
}
163+
);
164+
144165
/* @conditional-compile-remove(rooms) */
145166
const convertRemoteParticipantToParticipantListParticipantBetaRelease = (
146167
userId: string,
@@ -176,7 +197,8 @@ const convertRemoteParticipantToParticipantListParticipantBeta = (
176197
isSpeaking: boolean,
177198
raisedHand: RaisedHandState | undefined,
178199
localUserCanRemoveOthers: boolean,
179-
reaction: Reaction | undefined
200+
reaction: Reaction | undefined,
201+
isSpotlighted: Spotlight | undefined
180202
): CallParticipantListParticipant => {
181203
return {
182204
...convertRemoteParticipantToParticipantListParticipant(
@@ -189,6 +211,7 @@ const convertRemoteParticipantToParticipantListParticipantBeta = (
189211
raisedHand,
190212
localUserCanRemoveOthers
191213
),
192-
reaction
214+
reaction,
215+
isSpotlighted
193216
};
194217
};

packages/communication-react/review/beta/communication-react.api.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -895,6 +895,7 @@ export type CallParticipantListParticipant = ParticipantListParticipant & {
895895
isSpeaking?: boolean;
896896
raisedHand?: RaisedHand;
897897
reaction?: Reaction;
898+
isSpotlighted?: Spotlight;
898899
};
899900

900901
// @beta
@@ -2408,6 +2409,7 @@ export const DEFAULT_COMPONENT_ICONS: {
24082409
ParticipantItemOptions: React_2.JSX.Element;
24092410
ParticipantItemOptionsHovered: React_2.JSX.Element;
24102411
ParticipantItemScreenShareStart: React_2.JSX.Element;
2412+
ParticipantItemSpotlighted: React_2.JSX.Element;
24112413
HoldCallContextualMenuItem: React_2.JSX.Element;
24122414
HoldCallButton: React_2.JSX.Element;
24132415
ResumeCall: React_2.JSX.Element;
@@ -2551,6 +2553,7 @@ export const DEFAULT_COMPOSITE_ICONS: {
25512553
ErrorBarCallVideoRecoveredBySystem: React_2.JSX.Element;
25522554
ErrorBarCallVideoStoppedBySystem: React_2.JSX.Element;
25532555
MessageResend: React_2.JSX.Element;
2556+
ParticipantItemSpotlighted: React_2.JSX.Element;
25542557
HoldCallContextualMenuItem: React_2.JSX.Element;
25552558
HoldCallButton: React_2.JSX.Element;
25562559
ResumeCall: React_2.JSX.Element;
@@ -3931,6 +3934,11 @@ export interface SpokenLanguageStrings {
39313934
'zh-tw': string;
39323935
}
39333936

3937+
// @beta
3938+
export type Spotlight = {
3939+
spotlightOrderPosition?: number;
3940+
};
3941+
39343942
// @beta
39353943
export interface SpotlightCallFeatureState {
39363944
spotlightedParticipants: SpotlightedParticipant[];

packages/communication-react/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,8 @@ export type {
299299
export type { RaiseHandButtonProps, RaiseHandButtonStrings, RaisedHand } from '../../react-components/src';
300300
/* @conditional-compile-remove(reaction) */
301301
export type { ReactionButtonStrings, Reaction, ReactionButtonProps } from '../../react-components/src';
302+
/* @conditional-compile-remove(spotlight) */
303+
export type { Spotlight } from '../../react-components/src';
302304
/* @conditional-compile-remove(image-gallery) */
303305
export type { ImageGalleryProps, ImageGalleryImageProps, ImageGalleryStrings } from '../../react-components/src';
304306
/* @conditional-compile-remove(data-loss-prevention) */

packages/react-components/review/beta/react-components.api.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ export type CallParticipantListParticipant = ParticipantListParticipant & {
176176
isSpeaking?: boolean;
177177
raisedHand?: RaisedHand;
178178
reaction?: Reaction;
179+
isSpotlighted?: Spotlight;
179180
};
180181

181182
// @internal
@@ -815,6 +816,7 @@ export const DEFAULT_COMPONENT_ICONS: {
815816
ParticipantItemOptions: React_2.JSX.Element;
816817
ParticipantItemOptionsHovered: React_2.JSX.Element;
817818
ParticipantItemScreenShareStart: React_2.JSX.Element;
819+
ParticipantItemSpotlighted: React_2.JSX.Element;
818820
HoldCallContextualMenuItem: React_2.JSX.Element;
819821
HoldCallButton: React_2.JSX.Element;
820822
ResumeCall: React_2.JSX.Element;
@@ -2183,6 +2185,11 @@ export const _spokenLanguageToCaptionLanguage: {
21832185
'zh-tw': string;
21842186
};
21852187

2188+
// @beta
2189+
export type Spotlight = {
2190+
spotlightOrderPosition?: number;
2191+
};
2192+
21862193
// @internal
21872194
export const _StarSurvey: (props: _StarSurveyProps) => JSX.Element;
21882195

packages/react-components/src/components/ParticipantList.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,11 @@ const onRenderParticipantDefault = (
192192
{callingParticipant.isMuted && (
193193
<Icon iconName="ParticipantItemMicOff" className={iconStyles} ariaLabel={strings.mutedIconLabel} />
194194
)}
195+
{
196+
/* @conditional-compile-remove(spotlight) */ callingParticipant.isSpotlighted && (
197+
<Icon iconName="ParticipantItemSpotlighted" className={iconStyles} />
198+
)
199+
}
195200
</Stack>
196201
)
197202
: () => null;

packages/react-components/src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ export type {
6464
/* @conditional-compile-remove(raise-hand) */
6565
export type { RaisedHand } from './types';
6666

67+
/* @conditional-compile-remove(spotlight) */
68+
export type { Spotlight } from './types';
69+
6770
/* @conditional-compile-remove(reaction) */
6871
export type { Reaction } from './types';
6972

packages/react-components/src/theming/icons.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,8 @@ export const DEFAULT_COMPONENT_ICONS = {
311311
ParticipantItemOptions: <></>,
312312
ParticipantItemOptionsHovered: <MoreHorizontal20Filled />,
313313
ParticipantItemScreenShareStart: <ShareScreenStart20Filled />,
314+
/* @conditional-compile-remove(spotlight) */
315+
ParticipantItemSpotlighted: <VideoPersonStar20Filled />,
314316
/* @conditional-compile-remove(PSTN-calls) */
315317
HoldCallContextualMenuItem: <CallPause20Regular />,
316318
/* @conditional-compile-remove(PSTN-calls) */

0 commit comments

Comments
 (0)