Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"type": "patch",
"area": "fix",
"workstream": "",
"comment": "Ensure components re-render when adapter state changes by using useSelector instead of adapter.getState",
"packageName": "@azure/communication-react",
"email": "2684369+JamesBurnside@users.noreply.github.com",
"dependentChangeType": "patch"
}
13 changes: 13 additions & 0 deletions common/config/rush/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 18 additions & 3 deletions common/config/rush/variants/stable/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 16 additions & 1 deletion packages/react-composites/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

module.exports = {
env: {
browser: true,
Expand All @@ -14,7 +15,7 @@ module.exports = {
'plugin:react-hooks/recommended'
],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint', 'header', 'jsdoc'],
plugins: ['@typescript-eslint', 'header', 'jsdoc', '@internal/custom-rules'],
parserOptions: {
ecmaFeatures: {
jsx: true
Expand All @@ -23,6 +24,7 @@ module.exports = {
sourceType: 'module'
},
rules: {
'@internal/custom-rules/no-getstate': 'error',
'@typescript-eslint/explicit-function-return-type': [
'warn',
{
Expand Down Expand Up @@ -105,6 +107,19 @@ module.exports = {
rules: {
'jsdoc/require-jsdoc': 'off'
}
},
{
files: [
'tests/**/*',
'*.test.ts',
'AzureCommunicationCallAdapter.ts',
'AzureCommunicationCallWithChatAdapter.ts',
'useAdaptedSelector.ts',
'useHandlers.ts'
],
rules: {
'@internal/custom-rules/no-getstate': 'off'
}
}
]
};
1 change: 1 addition & 0 deletions packages/react-composites/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
"@babel/cli": "^7.24.8",
"@babel/core": "^7.25.2",
"@babel/preset-env": "7.23.9",
"@internal/eslint-plugin-custom-rules": "0.1.0",
"@internal/fake-backends": "1.20.0-beta.0",
"@microsoft/api-documenter": "~7.25.9",
"@microsoft/api-extractor": "~7.47.4",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ import { CallPage } from './pages/CallPage';
import { ConfigurationPage } from './pages/ConfigurationPage';
import { NoticePage } from './pages/NoticePage';
import { useSelector } from './hooks/useSelector';
import { getEndedCall, getPage, getTargetCallees } from './selectors/baseSelectors';
import { getAlternateCallerId, getEndedCall, getPage, getRole, getTargetCallees } from './selectors/baseSelectors';
/* @conditional-compile-remove(unsupported-browser) */
import { getEnvironmentInfo } from './selectors/baseSelectors';
import { LobbyPage } from './pages/LobbyPage';
import { TransferPage } from './pages/TransferPage';
import {
Expand Down Expand Up @@ -362,11 +364,11 @@ const MainScreen = (props: MainScreenProps): JSX.Element => {
const hasCameras = camerasCount > 0;
const hasMicrophones = microphonesCount > 0;

const role = useSelector(getRole);

useEffect(() => {
(async () => {
const constrain = getQueryOptions({
role: adapter.getState().call?.role
});
const constrain = getQueryOptions({ role });
/* @conditional-compile-remove(call-readiness) */
{
constrain.audio = props.options?.deviceChecks?.microphone === 'doNotPrompt' ? false : constrain.audio;
Expand All @@ -379,6 +381,7 @@ const MainScreen = (props: MainScreenProps): JSX.Element => {
})();
}, [
adapter,
role,
/* @conditional-compile-remove(call-readiness) */
props.options?.deviceChecks,
// Ensure we re-ask for permissions if the number of devices goes from 0 -> n during a call
Expand Down Expand Up @@ -527,7 +530,7 @@ const MainScreen = (props: MainScreenProps): JSX.Element => {
const callees = useSelector(getTargetCallees) as StartCallIdentifier[];
const locale = useLocale();
const palette = useTheme().palette;
const alternateCallerId = adapter.getState().alternateCallerId;
const alternateCallerId = useSelector(getAlternateCallerId);
const leavePageStyle = useMemo(() => leavingPageStyle(palette), [palette]);
let pageElement: JSX.Element | undefined;
const [pinnedParticipants, setPinnedParticipants] = useState<string[]>([]);
Expand Down Expand Up @@ -731,6 +734,9 @@ const MainScreen = (props: MainScreenProps): JSX.Element => {

useEndedCallConsoleErrors(endedCall);

/* @conditional-compile-remove(unsupported-browser) */
const environmentInfo = useSelector(getEnvironmentInfo);

/* @conditional-compile-remove(unsupported-browser) */
switch (page) {
case 'unsupportedEnvironment':
Expand All @@ -740,7 +746,7 @@ const MainScreen = (props: MainScreenProps): JSX.Element => {
/* @conditional-compile-remove(unsupported-browser) */
<UnsupportedBrowserPage
onTroubleshootingClick={props.options?.onEnvironmentInfoTroubleshootingClick}
environmentInfo={adapter.getState().environmentInfo}
environmentInfo={environmentInfo}
/>
}
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,14 @@ import { useSelector } from '../hooks/useSelector';
import { callStatusSelector } from '../selectors/callStatusSelector';
import { CallControlOptions } from '../types/CallControlOptions';
import { PreparedMoreDrawer } from '../../common/Drawer/PreparedMoreDrawer';
import { getIsTeamsMeeting, getRemoteParticipants } from '../selectors/baseSelectors';
import {
getCapabilites,
getIsTeamsMeeting,
getReactionResources,
getRemoteParticipants,
getRole,
getVideoEffectsDependency
} from '../selectors/baseSelectors';
import { getPage } from '../selectors/baseSelectors';
import { getCallStatus, getCaptionsStatus } from '../selectors/baseSelectors';
import { drawerContainerStyles } from '../styles/CallComposite.styles';
Expand Down Expand Up @@ -210,7 +217,7 @@ export const CallArrangement = (props: CallArrangementProps): JSX.Element => {
);

const locale = useLocale();
const role = adapter.getState().call?.role;
const role = useSelector(getRole);
const videoGalleryProps = usePropsFor(VideoGallery);
/* @conditional-compile-remove(soft-mute) */
const muteAllHandlers = useHandlers(MoreDrawer);
Expand Down Expand Up @@ -294,8 +301,7 @@ export const CallArrangement = (props: CallArrangementProps): JSX.Element => {
setPromptProps
);

const canRemoveSpotlight =
adapter.getState().call?.capabilitiesFeature?.capabilities.removeParticipantsSpotlight.isPresent;
const canRemoveSpotlight = useSelector(getCapabilites)?.removeParticipantsSpotlight.isPresent;
const stopAllSpotlight = useMemo(
() => (canRemoveSpotlight ? () => adapter.stopAllSpotlight() : undefined),
[canRemoveSpotlight, adapter]
Expand Down Expand Up @@ -393,7 +399,7 @@ export const CallArrangement = (props: CallArrangementProps): JSX.Element => {
};
}, [isMobileWithActivePane, props.mobileView]);

const onResolveVideoEffectDependency = adapter.getState().onResolveVideoEffectDependency;
const onResolveVideoEffectDependency = useSelector(getVideoEffectsDependency);

const { openVideoEffectsPane } = useVideoEffectsPane(
props.updateSidePaneRenderer,
Expand Down Expand Up @@ -495,6 +501,8 @@ export const CallArrangement = (props: CallArrangementProps): JSX.Element => {
? (latestNotifications ?? []).filter((notification) => notification.type !== 'assignedBreakoutRoomOpenedPromptJoin')
: latestNotifications;

const reactionResources = useSelector(getReactionResources);

return (
<div ref={containerRef} className={mergeStyles(containerDivStyles)} id={props.id}>
<Stack verticalFill horizontalAlign="stretch" className={containerClassName} data-ui-id={props.dataUiId}>
Expand Down Expand Up @@ -573,7 +581,7 @@ export const CallArrangement = (props: CallArrangementProps): JSX.Element => {
userSetGalleryLayout={props.userSetGalleryLayout}
onSetDialpadPage={props.onSetDialpadPage}
dtmfDialerPresent={props.dtmfDialerPresent}
reactionResources={adapter.getState().reactions}
reactionResources={reactionResources}
onClickMeetingPhoneInfo={onMeetingPhoneInfoClicked}
/>
</Stack>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ import { useLocale } from '../../localization';
import { MoreButton } from '../../common/MoreButton';
import { usePropsFor } from '../hooks/usePropsFor';
import { buttonFlyoutIncreasedSizeStyles } from '../styles/Buttons.styles';
/* @conditional-compile-remove(DNS) */
import { useAdapter } from '../adapter/CallAdapterProvider';
import { isDisabled } from '../utils';
import { callControlsContainerStyles } from '../styles/CallPage.styles';
import { CommonCallAdapter } from '../adapter';
import { RaiseHand } from './buttons/RaiseHand';
import { RaiseHandButton, RaiseHandButtonProps } from '@internal/react-components';
import { _generateDefaultDeviceMenuProps } from '@internal/react-components';
Expand All @@ -42,6 +42,15 @@ import { capabilitySelector } from '../../CallComposite/selectors/capabilitySele
import { callStatusSelector } from '../../CallComposite/selectors/callStatusSelector';
/* @conditional-compile-remove(DNS) */
import { _isSafari } from '../../CallComposite/utils';
import { getIsRoomsCall, getReactionResources, getRole } from '../selectors/baseSelectors';
/* @conditional-compile-remove(calling-environment-info) */
import { getEnvironmentInfo } from '../selectors/baseSelectors';
/* @conditional-compile-remove(DNS) */
import {
getDeepNoiseSuppresionEffectsDependency,
getDeepNoiseSuppresionIsOnByDefault,
getHideDeepNoiseSupressionButton
} from '../selectors/baseSelectors';

/**
* @private
Expand Down Expand Up @@ -89,41 +98,43 @@ export const CallControls = (props: CallControlsProps & ContainerRectProps): JSX
[props.isMobile, props.options]
);

const adapter = useAdapter();

const localeStrings = useLocale();

/* @conditional-compile-remove(DNS) */
const [isDeepNoiseSuppressionOn, setDeepNoiseSuppressionOn] = useState<boolean>(false);

/* @conditional-compile-remove(DNS) */
const adapter = useAdapter();
/* @conditional-compile-remove(DNS) */
const startDeepNoiseSuppression = useCallback(async () => {
await adapter.startNoiseSuppressionEffect();
}, [adapter]);

/* @conditional-compile-remove(DNS) */
const deepNoiseSuppresionEffectsDependency = useSelector(getDeepNoiseSuppresionEffectsDependency);
/* @conditional-compile-remove(DNS) */
const deepNoiseSuppressionOnByDefault = useSelector(getDeepNoiseSuppresionIsOnByDefault);
/* @conditional-compile-remove(DNS) */
useEffect(() => {
if (
adapter.getState().onResolveDeepNoiseSuppressionDependency &&
adapter.getState().deepNoiseSuppressionOnByDefault
) {
if (deepNoiseSuppresionEffectsDependency && deepNoiseSuppressionOnByDefault) {
startDeepNoiseSuppression();
setDeepNoiseSuppressionOn(true);
}
}, [adapter, startDeepNoiseSuppression]);
}, [deepNoiseSuppresionEffectsDependency, deepNoiseSuppressionOnByDefault, startDeepNoiseSuppression]);

/* @conditional-compile-remove(DNS) */
const environmentInfo = adapter.getState().environmentInfo;
const environmentInfo = useSelector(getEnvironmentInfo);

/* @conditional-compile-remove(DNS) */
const isSafari = _isSafari(environmentInfo);
/* @conditional-compile-remove(DNS) */
const showNoiseSuppressionButton =
adapter.getState().onResolveDeepNoiseSuppressionDependency &&
!adapter.getState().hideDeepNoiseSuppressionButton &&
const hideDeepNoiseSuppressionButton = useSelector(getHideDeepNoiseSupressionButton);
/* @conditional-compile-remove(DNS) */
const showNoiseSuppressionButton = !!(
Comment thread
vhuseinova-msft marked this conversation as resolved.
deepNoiseSuppresionEffectsDependency &&
!hideDeepNoiseSuppressionButton &&
!isSafari
? true
: false;
);

/* @conditional-compile-remove(DNS) */
const onClickNoiseSuppression = useCallback(async () => {
Expand Down Expand Up @@ -197,6 +208,8 @@ export const CallControls = (props: CallControlsProps & ContainerRectProps): JSX
numberOfButtons++;
}

const isRoomsCall = useSelector(getIsRoomsCall);

const moreButtonContextualMenuItems = (): IContextualMenuItem[] => {
const items: IContextualMenuItem[] = [];

Expand All @@ -218,7 +231,7 @@ export const CallControls = (props: CallControlsProps & ContainerRectProps): JSX
});
}

if (!isRoomsCallTrampoline(adapter)) {
if (!isRoomsCall) {
items.push({
key: 'holdButtonKey',
text: localeStrings.component.strings.holdButton.tooltipOffContent,
Expand Down Expand Up @@ -267,12 +280,11 @@ export const CallControls = (props: CallControlsProps & ContainerRectProps): JSX
showMoreButton = isEnabled(options?.moreButton);
}

const reactionResources = adapter.getState().reactions;
const reactionResources = useSelector(getReactionResources);
const raiseHandButtonIsEnabled = isEnabled(options?.raiseHandButton);
let showRaiseHandButtonInControlBar = raiseHandButtonIsEnabled;
const role = adapter.getState().call?.role;
const hideRaiseHandButtonInRoomsCall =
adapter.getState().isRoomsCall && role && ['Consumer', 'Unknown'].includes(role);
const role = useSelector(getRole);
const hideRaiseHandButtonInRoomsCall = isRoomsCall && role && ['Consumer', 'Unknown'].includes(role);
if (showRaiseHandButtonInControlBar && (props.isMobile ? numberOfButtons < 5 : true)) {
numberOfButtons++;
} else {
Expand Down Expand Up @@ -470,8 +482,3 @@ export const CallControls = (props: CallControlsProps & ContainerRectProps): JSX
};

const isEnabled = (option: unknown): boolean => option !== false;

/** @private */
export const isRoomsCallTrampoline = (adapter: CommonCallAdapter): boolean => {
return adapter.getState().isRoomsCall;
};
Loading