Skip to content

Commit 9619d5c

Browse files
committed
fix reviews
1 parent 1ba1a12 commit 9619d5c

File tree

4 files changed

+62
-100
lines changed

4 files changed

+62
-100
lines changed

app/containers/MediaCallHeader/MediaCallHeader.test.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,12 +89,8 @@ describe('MediaCallHeader', () => {
8989
expect(queryByTestId('media-call-header-end')).toBeNull();
9090
});
9191

92-
it('should render empty placeholder when only callId is set (native accepted call, before answerCall completes)', () => {
93-
useCallStore.setState({
94-
call: null,
95-
callId: 'e3246c4d-d23a-412f-8a8b-37ec9f29ef1a',
96-
callState: 'none'
97-
});
92+
it('should render empty placeholder when native accepted but call not bound yet (before answerCall completes)', () => {
93+
useCallStore.getState().setNativeAcceptedCallId('e3246c4d-d23a-412f-8a8b-37ec9f29ef1a');
9894
const { getByTestId, queryByTestId } = render(
9995
<Wrapper>
10096
<MediaCallHeader />

app/lib/services/voip/MediaSessionInstance.test.ts

Lines changed: 9 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ const mockCallStoreReset = jest.fn();
66
const mockUseCallStoreGetState = jest.fn(() => ({
77
reset: mockCallStoreReset,
88
setCall: jest.fn(),
9-
setCallId: jest.fn(),
109
resetNativeCallId: jest.fn(),
1110
call: null as unknown,
1211
callId: null as string | null,
@@ -98,14 +97,17 @@ jest.mock('@rocket.chat/media-signaling', () => ({
9897
})
9998
}));
10099

100+
const STREAM_NOTIFY_USER = 'stream-notify-user';
101+
101102
function getStreamNotifyHandler(): (ddpMessage: IDDPMessage) => void {
102103
const calls = mockOnStreamData.mock.calls as unknown as [string, (m: IDDPMessage) => void][];
103-
const last = calls[calls.length - 1];
104-
const handler = last?.[1];
105-
if (typeof handler !== 'function') {
106-
throw new Error('stream-notify-user handler not registered');
104+
for (let i = calls.length - 1; i >= 0; i--) {
105+
const [eventName, handler] = calls[i];
106+
if (eventName === STREAM_NOTIFY_USER && typeof handler === 'function') {
107+
return handler;
108+
}
107109
}
108-
return handler;
110+
throw new Error('stream-notify-user handler not registered');
109111
}
110112

111113
describe('MediaSessionInstance', () => {
@@ -115,7 +117,6 @@ describe('MediaSessionInstance', () => {
115117
mockUseCallStoreGetState.mockReturnValue({
116118
reset: mockCallStoreReset,
117119
setCall: jest.fn(),
118-
setCallId: jest.fn(),
119120
resetNativeCallId: jest.fn(),
120121
call: null,
121122
callId: null,
@@ -197,40 +198,8 @@ describe('MediaSessionInstance', () => {
197198
});
198199

199200
describe('stream-notify-user (notification/accepted gated)', () => {
200-
it('does not call answerCall when store has no native-accepted callId', async () => {
201-
const answerSpy = jest.spyOn(mediaSessionInstance, 'answerCall').mockResolvedValue(undefined);
202-
mediaSessionInstance.init('user-1');
203-
const streamHandler = getStreamNotifyHandler();
204-
streamHandler({
205-
msg: 'changed',
206-
fields: {
207-
eventName: 'uid/media-signal',
208-
args: [
209-
{
210-
type: 'notification',
211-
notification: 'accepted',
212-
signedContractId: 'test-device-id',
213-
callId: 'from-signal'
214-
}
215-
]
216-
}
217-
});
218-
await Promise.resolve();
219-
expect(answerSpy).not.toHaveBeenCalled();
220-
answerSpy.mockRestore();
221-
});
222-
223-
it('does not call answerCall when transient callId matches signal but nativeAcceptedCallId does not', async () => {
201+
it('does not call answerCall when nativeAcceptedCallId is null', async () => {
224202
const answerSpy = jest.spyOn(mediaSessionInstance, 'answerCall').mockResolvedValue(undefined);
225-
mockUseCallStoreGetState.mockReturnValue({
226-
reset: mockCallStoreReset,
227-
setCall: jest.fn(),
228-
setCallId: jest.fn(),
229-
resetNativeCallId: jest.fn(),
230-
call: null,
231-
callId: 'from-signal',
232-
nativeAcceptedCallId: null
233-
});
234203
mediaSessionInstance.init('user-1');
235204
const streamHandler = getStreamNotifyHandler();
236205
streamHandler({
@@ -257,7 +226,6 @@ describe('MediaSessionInstance', () => {
257226
mockUseCallStoreGetState.mockReturnValue({
258227
reset: mockCallStoreReset,
259228
setCall: jest.fn(),
260-
setCallId: jest.fn(),
261229
resetNativeCallId: jest.fn(),
262230
call: null,
263231
callId: null,
@@ -289,7 +257,6 @@ describe('MediaSessionInstance', () => {
289257
mockUseCallStoreGetState.mockReturnValue({
290258
reset: mockCallStoreReset,
291259
setCall: jest.fn(),
292-
setCallId: jest.fn(),
293260
resetNativeCallId: jest.fn(),
294261
call: null,
295262
callId: null,
@@ -321,7 +288,6 @@ describe('MediaSessionInstance', () => {
321288
mockUseCallStoreGetState.mockReturnValue({
322289
reset: mockCallStoreReset,
323290
setCall: jest.fn(),
324-
setCallId: jest.fn(),
325291
resetNativeCallId: jest.fn(),
326292
call: { callId: 'from-signal' } as any,
327293
callId: 'from-signal',

app/lib/services/voip/useCallStore.ts

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const STALE_NATIVE_MS = 15_000;
1010

1111
let callListenersCleanup: (() => void) | null = null;
1212
let staleNativeTimer: ReturnType<typeof setTimeout> | null = null;
13-
/** Id this timer may clear; must match `nativeAcceptedCallId` at fire time. */
13+
/** Call id this timer is for; only `nativeAcceptedCallId` is cleared when it fires, not `callId`. */
1414
let staleNativeScheduledId: string | null = null;
1515

1616
export function cleanupCallListeners(): void {
@@ -26,7 +26,15 @@ function cancelStaleNativeTimer(): void {
2626
staleNativeScheduledId = null;
2727
}
2828

29-
function armStaleNativeTimer(get: () => CallStore): void {
29+
function clearStaleNativeIfStillUnbound(get: () => CallStore, scheduled: string): void {
30+
const st = get();
31+
if (st.call != null || st.nativeAcceptedCallId !== scheduled) {
32+
return;
33+
}
34+
useCallStore.setState({ nativeAcceptedCallId: null });
35+
}
36+
37+
function createStaleNativeTimer(get: () => CallStore): void {
3038
cancelStaleNativeTimer();
3139
const scheduledId = get().nativeAcceptedCallId;
3240
if (scheduledId == null || scheduledId === '') {
@@ -35,19 +43,11 @@ function armStaleNativeTimer(get: () => CallStore): void {
3543
staleNativeScheduledId = scheduledId;
3644
staleNativeTimer = setTimeout(() => {
3745
staleNativeTimer = null;
38-
const scheduled = staleNativeScheduledId;
39-
staleNativeScheduledId = null;
40-
const st = get();
41-
if (st.call != null) {
42-
return;
43-
}
44-
if (st.nativeAcceptedCallId !== scheduled) {
45-
return;
46+
// Timer uses the id from when it was created, not the current module variable.
47+
if (staleNativeScheduledId === scheduledId) {
48+
staleNativeScheduledId = null;
4649
}
47-
useCallStore.setState({
48-
nativeAcceptedCallId: null,
49-
callId: null
50-
});
50+
clearStaleNativeIfStillUnbound(get, scheduledId);
5151
}, STALE_NATIVE_MS);
5252
}
5353

@@ -75,18 +75,17 @@ interface CallStoreState {
7575
}
7676

7777
interface CallStoreActions {
78-
setCallId: (callId: string | null) => void;
79-
/** Native accept paths: sets sticky id only; starts/restarts stale-native timer. */
78+
/** Sets native-accepted call id and (re)starts the 15s timer. */
8079
setNativeAcceptedCallId: (callId: string) => void;
81-
/** Clears sticky native id (+ transient `callId` when unbound); cancels stale timer. */
80+
/** Clears native-accepted id and related state; cancels the timer. */
8281
resetNativeCallId: () => void;
8382
setCall: (call: IClientMediaCall) => void;
8483
toggleMute: () => void;
8584
toggleHold: () => void;
8685
toggleSpeaker: () => void;
8786
toggleFocus: () => void;
8887
endCall: () => void;
89-
/** Clears ring/UI/transient fields; preserves `nativeAcceptedCallId`; restarts stale timer when id preserved. */
88+
/** Clears UI/call fields but keeps nativeAcceptedCallId. Restarts the 15s timer (media init calls reset and clears the old timer first). */
9089
reset: () => void;
9190
setDialpadValue: (value: string) => void;
9291
}
@@ -112,14 +111,10 @@ const initialState: CallStoreState = {
112111
export const useCallStore = create<CallStore>((set, get) => ({
113112
...initialState,
114113

115-
setCallId: (callId: string | null) => {
116-
set({ callId });
117-
},
118-
119114
setNativeAcceptedCallId: (callId: string) => {
120115
cancelStaleNativeTimer();
121116
set({ nativeAcceptedCallId: callId });
122-
armStaleNativeTimer(get);
117+
createStaleNativeTimer(get);
123118
},
124119

125120
resetNativeCallId: () => {
@@ -278,7 +273,8 @@ export const useCallStore = create<CallStore>((set, get) => ({
278273
}
279274
set({ ...initialState, nativeAcceptedCallId });
280275
hideActionSheetRef();
281-
armStaleNativeTimer(get);
276+
// Old timer was cleared above; start a new one if nativeAcceptedCallId is still set.
277+
createStaleNativeTimer(get);
282278
}
283279
}));
284280

yarn.lock

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5059,11 +5059,6 @@
50595059
dependencies:
50605060
typia "~9.7.2"
50615061

5062-
"@rtsao/scc@^1.1.0":
5063-
version "1.1.0"
5064-
resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8"
5065-
integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==
5066-
50675062
"@samchon/openapi@^4.7.1":
50685063
version "4.7.2"
50695064
resolved "https://registry.yarnpkg.com/@samchon/openapi/-/openapi-4.7.2.tgz#b00c54b587b22e03e454ff58989c4a63144850b3"
@@ -5110,6 +5105,13 @@
51105105
resolved "https://registry.yarnpkg.com/@standard-schema/spec/-/spec-1.1.0.tgz#a79b55dbaf8604812f52d140b2c9ab41bc150bb8"
51115106
integrity sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==
51125107

5108+
"@storybook/csf@^0.1.13":
5109+
version "0.1.13"
5110+
resolved "https://registry.yarnpkg.com/@storybook/csf/-/csf-0.1.13.tgz#c8a9bea2ae518a3d9700546748fa30a8b07f7f80"
5111+
integrity sha512-7xOOwCLGB3ebM87eemep89MYRFTko+D8qE7EdAAq74lgdqRR5cOUtYWJLjO2dLtP94nqoOdHJo6MdLLKzg412Q==
5112+
dependencies:
5113+
type-fest "^2.19.0"
5114+
51135115
"@storybook/global@^5.0.0":
51145116
version "5.0.0"
51155117
resolved "https://registry.yarnpkg.com/@storybook/global/-/global-5.0.0.tgz#b793d34b94f572c1d7d9e0f44fac4e0dbc9572ed"
@@ -6171,20 +6173,6 @@ array-includes@^3.1.4, array-includes@^3.1.6, array-includes@^3.1.7:
61716173
get-intrinsic "^1.2.4"
61726174
is-string "^1.0.7"
61736175

6174-
array-includes@^3.1.8, array-includes@^3.1.9:
6175-
version "3.1.9"
6176-
resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.9.tgz#1f0ccaa08e90cdbc3eb433210f903ad0f17c3f3a"
6177-
integrity sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==
6178-
dependencies:
6179-
call-bind "^1.0.8"
6180-
call-bound "^1.0.4"
6181-
define-properties "^1.2.1"
6182-
es-abstract "^1.24.0"
6183-
es-object-atoms "^1.1.1"
6184-
get-intrinsic "^1.3.0"
6185-
is-string "^1.1.1"
6186-
math-intrinsics "^1.1.0"
6187-
61886176
array-timsort@^1.0.3:
61896177
version "1.0.3"
61906178
resolved "https://registry.yarnpkg.com/array-timsort/-/array-timsort-1.0.3.tgz#3c9e4199e54fb2b9c3fe5976396a21614ef0d926"
@@ -6356,10 +6344,10 @@ axe-core@=4.7.0:
63566344
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.7.0.tgz#34ba5a48a8b564f67e103f0aa5768d76e15bbbbf"
63576345
integrity sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==
63586346

6359-
axios@0.28.0:
6360-
version "0.28.0"
6361-
resolved "https://registry.yarnpkg.com/axios/-/axios-0.28.0.tgz#801a4d991d0404961bccef46800e1170f8278c89"
6362-
integrity sha512-Tu7NYoGY4Yoc7I+Npf9HhUMtEEpV7ZiLH9yndTCoNhcpBH0kwcvFbzYN9/u5QKI5A6uefjsNNWaz5olJVYS62Q==
6347+
axios@~0.28.1:
6348+
version "0.28.1"
6349+
resolved "https://registry.yarnpkg.com/axios/-/axios-0.28.1.tgz#2a7bcd34a3837b71ee1a5ca3762214b86b703e70"
6350+
integrity sha512-iUcGA5a7p0mVb4Gm/sy+FSECNkPFT4y7wt6OM/CDpO/OnNCvSs3PoMG8ibrC9jRoGYU0gUK5pXVC4NPXq6lHRQ==
63636351
dependencies:
63646352
follow-redirects "^1.15.0"
63656353
form-data "^4.0.0"
@@ -6740,7 +6728,7 @@ buffer@^5.4.3, buffer@^5.5.0:
67406728
base64-js "^1.3.1"
67416729
ieee754 "^1.1.13"
67426730

6743-
bytebuffer@5.0.1:
6731+
bytebuffer@~5.0.1:
67446732
version "5.0.1"
67456733
resolved "https://registry.yarnpkg.com/bytebuffer/-/bytebuffer-5.0.1.tgz#582eea4b1a873b6d020a48d58df85f0bba6cfddd"
67466734
integrity sha512-IuzSdmADppkZ6DlpycMkm8l9zeEq16fWtLvunEwFiYciR/BHo4E8/xs5piFquG+Za8OWmMqHF8zuRviz2LHvRQ==
@@ -6977,6 +6965,14 @@ cli-spinners@^2.0.0, cli-spinners@^2.5.0:
69776965
resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.2.tgz#1773a8f4b9c4d6ac31563df53b3fc1d79462fe41"
69786966
integrity sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==
69796967

6968+
cli-truncate@^2.1.0:
6969+
version "2.1.0"
6970+
resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7"
6971+
integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==
6972+
dependencies:
6973+
slice-ansi "^3.0.0"
6974+
string-width "^4.2.0"
6975+
69806976
cli-width@^3.0.0:
69816977
version "3.0.0"
69826978
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6"
@@ -7730,7 +7726,7 @@ drange@^1.0.2:
77307726
resolved "https://registry.yarnpkg.com/drange/-/drange-1.1.1.tgz#b2aecec2aab82fcef11dbbd7b9e32b83f8f6c0b8"
77317727
integrity sha512-pYxfDYpued//QpnLIm4Avk7rsNtAtQkUES2cwAYSvD/wd2pKD71gN2Ebj3e7klzXwjocvE8c5vx/1fxwpqmSxA==
77327728

7733-
dunder-proto@^1.0.0, dunder-proto@^1.0.1:
7729+
dunder-proto@^1.0.1:
77347730
version "1.0.1"
77357731
resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a"
77367732
integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==
@@ -13580,7 +13576,7 @@ run-parallel@^1.1.9:
1358013576
dependencies:
1358113577
queue-microtask "^1.2.2"
1358213578

13583-
rxjs@^7.5.5, rxjs@^7.8.1:
13579+
rxjs@^7.5.1, rxjs@^7.5.5, rxjs@^7.8.1:
1358413580
version "7.8.2"
1358513581
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.2.tgz#955bc473ed8af11a002a2be52071bf475638607b"
1358613582
integrity sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==
@@ -14601,7 +14597,15 @@ throat@^5.0.0:
1460114597
resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b"
1460214598
integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==
1460314599

14604-
through@^2.3.6:
14600+
through2@^2.0.1:
14601+
version "2.0.5"
14602+
resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd"
14603+
integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==
14604+
dependencies:
14605+
readable-stream "~2.3.6"
14606+
xtend "~4.0.1"
14607+
14608+
through@^2.3.6, through@^2.3.8:
1460514609
version "2.3.8"
1460614610
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
1460714611
integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==

0 commit comments

Comments
 (0)