Skip to content

Commit f30f3b8

Browse files
Regaddinienkedekker
andcommitted
add useDailyError hook and improve error callbacks for nonfatal errors
Co-Authored-By: Nienke Dekker <nienkedekker@gmail.com>
1 parent 97d4584 commit f30f3b8

File tree

7 files changed

+176
-21
lines changed

7 files changed

+176
-21
lines changed

src/DailyMeeting.tsx

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import {
2+
DailyEventObjectFatalError,
3+
DailyEventObjectNonFatalError,
24
DailyMeetingSessionState,
35
DailyMeetingState,
46
} from '@daily-co/daily-js';
@@ -14,6 +16,16 @@ export const meetingStateState = atom<DailyMeetingState>({
1416
default: 'new',
1517
});
1618

19+
export const meetingErrorState = atom<DailyEventObjectFatalError | null>({
20+
key: RECOIL_PREFIX + 'meeting-error',
21+
default: null,
22+
});
23+
24+
export const nonFatalErrorState = atom<DailyEventObjectNonFatalError | null>({
25+
key: RECOIL_PREFIX + 'non-fatal-error',
26+
default: null,
27+
});
28+
1729
export const meetingSessionDataState = atom<DailyMeetingSessionState>({
1830
key: 'meeting-session-data',
1931
default: {
@@ -46,7 +58,27 @@ export const DailyMeeting: React.FC<React.PropsWithChildren<{}>> = ({
4658
useDailyEvent('joining-meeting', updateMeetingState);
4759
useDailyEvent('joined-meeting', updateMeetingState);
4860
useDailyEvent('left-meeting', updateMeetingState);
49-
useDailyEvent('error', updateMeetingState);
61+
useDailyEvent(
62+
'error',
63+
useRecoilCallback(
64+
({ set }) =>
65+
(ev) => {
66+
set(meetingErrorState, ev);
67+
updateMeetingState();
68+
},
69+
[updateMeetingState]
70+
)
71+
);
72+
useDailyEvent(
73+
'nonfatal-error',
74+
useRecoilCallback(
75+
({ set }) =>
76+
(ev) => {
77+
set(nonFatalErrorState, ev);
78+
},
79+
[]
80+
)
81+
);
5082

5183
/**
5284
* Updates meeting session state.

src/hooks/useDailyError.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { useRecoilValue } from 'recoil';
2+
3+
import { meetingErrorState, nonFatalErrorState } from '../DailyMeeting';
4+
5+
/**
6+
* Returns a meeting's last known errors.
7+
*/
8+
export const useDailyError = () => {
9+
const meetingError = useRecoilValue(meetingErrorState);
10+
const nonFatalError = useRecoilValue(nonFatalErrorState);
11+
return {
12+
meetingError,
13+
nonFatalError,
14+
};
15+
};

src/hooks/useInputSettings.ts

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,40 @@
11
import {
22
DailyCall,
33
DailyEventObject,
4+
DailyEventObjectNonFatalError,
45
DailyInputSettings,
56
} from '@daily-co/daily-js';
67
import { useCallback, useEffect } from 'react';
78
import { atom, useRecoilCallback, useRecoilValue } from 'recoil';
89

910
import { RECOIL_PREFIX } from '../lib/constants';
11+
import { Reconstruct } from '../types/Reconstruct';
1012
import { useDaily } from './useDaily';
13+
import { useDailyError } from './useDailyError';
1114
import { useDailyEvent } from './useDailyEvent';
1215

16+
type DailyEventObjectInputSettingsError = Reconstruct<
17+
DailyEventObjectNonFatalError,
18+
'type',
19+
'input-settings-error'
20+
>;
21+
1322
interface UseInputSettingsArgs {
14-
onError?(ev: DailyEventObject<'nonfatal-error'>): void;
23+
onError?(ev: DailyEventObjectInputSettingsError): void;
1524
onInputSettingsUpdated?(ev: DailyEventObject<'input-settings-updated'>): void;
1625
}
1726

1827
const inputSettingsState = atom<DailyInputSettings | null>({
1928
key: RECOIL_PREFIX + 'input-settings',
2029
default: null,
2130
});
22-
const errorState = atom<string | null>({
23-
key: RECOIL_PREFIX + 'input-settings-error',
24-
default: null,
25-
});
2631

2732
export const useInputSettings = ({
2833
onError,
2934
onInputSettingsUpdated,
3035
}: UseInputSettingsArgs = {}) => {
3136
const inputSettings = useRecoilValue(inputSettingsState);
32-
const errorMsg = useRecoilValue(errorState);
37+
const { nonFatalError } = useDailyError();
3338
const daily = useDaily();
3439

3540
const updateInputSettingsState = useRecoilCallback(
@@ -64,13 +69,11 @@ export const useInputSettings = ({
6469
*/
6570
useDailyEvent(
6671
'nonfatal-error',
67-
useRecoilCallback(
68-
({ set }) =>
69-
(ev) => {
70-
if (ev.type !== 'input-settings-error') return;
71-
set(errorState, ev.errorMsg);
72-
onError?.(ev);
73-
},
72+
useCallback(
73+
(ev) => {
74+
if (ev.type !== 'input-settings-error') return;
75+
onError?.(ev as DailyEventObjectInputSettingsError);
76+
},
7477
[onError]
7578
)
7679
);
@@ -86,7 +89,10 @@ export const useInputSettings = ({
8689
);
8790

8891
return {
89-
errorMsg,
92+
errorMsg:
93+
nonFatalError?.type === 'input-settings-error'
94+
? nonFatalError.errorMsg
95+
: null,
9096
inputSettings,
9197
updateInputSettings,
9298
};

src/hooks/useLiveStreaming.ts

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,28 @@
1-
import { DailyCall, DailyEventObject } from '@daily-co/daily-js';
1+
import {
2+
DailyCall,
3+
DailyEventObject,
4+
DailyEventObjectNonFatalError,
5+
} from '@daily-co/daily-js';
26
import { useCallback } from 'react';
37
import { useRecoilValue } from 'recoil';
48

59
import { liveStreamingState } from '../DailyLiveStreaming';
10+
import { Reconstruct } from '../types/Reconstruct';
611
import { useDaily } from './useDaily';
712
import { useDailyEvent } from './useDailyEvent';
813

14+
type DailyEventObjectLiveStreamingWarning = Reconstruct<
15+
DailyEventObjectNonFatalError,
16+
'type',
17+
'live-streaming-warning'
18+
>;
19+
920
interface UseLiveStreamingArgs {
1021
onLiveStreamingStarted?(ev: DailyEventObject<'live-streaming-started'>): void;
1122
onLiveStreamingStopped?(ev: DailyEventObject<'live-streaming-stopped'>): void;
1223
onLiveStreamingUpdated?(ev: DailyEventObject<'live-streaming-updated'>): void;
1324
onLiveStreamingError?(ev: DailyEventObject<'live-streaming-error'>): void;
25+
onLiveStreamingWarning?(ev: DailyEventObjectLiveStreamingWarning): void;
1426
}
1527

1628
/**
@@ -24,6 +36,7 @@ export const useLiveStreaming = ({
2436
onLiveStreamingStarted,
2537
onLiveStreamingStopped,
2638
onLiveStreamingUpdated,
39+
onLiveStreamingWarning,
2740
}: UseLiveStreamingArgs = {}) => {
2841
const daily = useDaily();
2942
const state = useRecoilValue(liveStreamingState);
@@ -37,7 +50,6 @@ export const useLiveStreaming = ({
3750
[onLiveStreamingStarted]
3851
)
3952
);
40-
4153
useDailyEvent(
4254
'live-streaming-stopped',
4355
useCallback(
@@ -47,7 +59,6 @@ export const useLiveStreaming = ({
4759
[onLiveStreamingStopped]
4860
)
4961
);
50-
5162
useDailyEvent(
5263
'live-streaming-updated',
5364
useCallback(
@@ -57,7 +68,6 @@ export const useLiveStreaming = ({
5768
[onLiveStreamingUpdated]
5869
)
5970
);
60-
6171
useDailyEvent(
6272
'live-streaming-error',
6373
useCallback(
@@ -67,6 +77,16 @@ export const useLiveStreaming = ({
6777
[onLiveStreamingError]
6878
)
6979
);
80+
useDailyEvent(
81+
'nonfatal-error',
82+
useCallback(
83+
(ev) => {
84+
if (ev.type !== 'live-streaming-warning') return;
85+
onLiveStreamingWarning?.(ev as DailyEventObjectLiveStreamingWarning);
86+
},
87+
[onLiveStreamingWarning]
88+
)
89+
);
7090

7191
const startLiveStreaming = useCallback(
7292
(...args: Parameters<DailyCall['startLiveStreaming']>) => {

src/hooks/useMeetingSessionState.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,38 @@
1+
import { DailyEventObjectNonFatalError } from '@daily-co/daily-js';
2+
import { useCallback } from 'react';
13
import { useRecoilValue } from 'recoil';
24

35
import { meetingSessionDataState } from '../DailyMeeting';
6+
import { Reconstruct } from '../types/Reconstruct';
7+
import { useDailyEvent } from './useDailyEvent';
8+
9+
type DailyEventObjectMeetingSessionDataError = Reconstruct<
10+
DailyEventObjectNonFatalError,
11+
'type',
12+
'meeting-session-data-error'
13+
>;
14+
15+
interface Props {
16+
onError?(ev: DailyEventObjectMeetingSessionDataError): void;
17+
}
418

519
/**
620
* Returns a meeting's current session data and topology.
721
*/
8-
export const useMeetingSessionState = <T = any>() => {
22+
export const useMeetingSessionState = <T = any>({ onError }: Props = {}) => {
923
const meetingSessionState = useRecoilValue(meetingSessionDataState);
24+
25+
useDailyEvent(
26+
'nonfatal-error',
27+
useCallback(
28+
(ev) => {
29+
if (ev.type !== 'meeting-session-data-error') return;
30+
onError?.(ev as DailyEventObjectMeetingSessionDataError);
31+
},
32+
[onError]
33+
)
34+
);
35+
1036
return {
1137
data: meetingSessionState?.data as T,
1238
topology: meetingSessionState?.topology,

src/hooks/useScreenShare.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1-
import { DailyCall, DailyTrackState } from '@daily-co/daily-js';
1+
import {
2+
DailyCall,
3+
DailyEventObjectNonFatalError,
4+
DailyTrackState,
5+
} from '@daily-co/daily-js';
26
import { useCallback } from 'react';
37

48
import { useScreenSharesContext } from '../DailyScreenShares';
9+
import { Reconstruct } from '../types/Reconstruct';
510
import { useDaily } from './useDaily';
611
import { useDailyEvent } from './useDailyEvent';
712

@@ -13,7 +18,14 @@ export interface ScreenShare {
1318
session_id: string;
1419
}
1520

21+
type DailyEventObjectScreenShareError = Reconstruct<
22+
DailyEventObjectNonFatalError,
23+
'type',
24+
'screen-share-error'
25+
>;
26+
1627
interface UseScreenShareArgs {
28+
onError?(ev: DailyEventObjectScreenShareError): void;
1729
onLocalScreenShareStarted?(): void;
1830
onLocalScreenShareStopped?(): void;
1931
}
@@ -22,6 +34,7 @@ interface UseScreenShareArgs {
2234
* Allows access to information about shared screens, and methods to start or stop a local screen share.
2335
*/
2436
export const useScreenShare = ({
37+
onError,
2538
onLocalScreenShareStarted,
2639
onLocalScreenShareStopped,
2740
}: UseScreenShareArgs = {}) => {
@@ -55,6 +68,16 @@ export const useScreenShare = ({
5568
[onLocalScreenShareStopped]
5669
)
5770
);
71+
useDailyEvent(
72+
'nonfatal-error',
73+
useCallback(
74+
(ev) => {
75+
if (ev.type !== 'screen-share-error') return;
76+
onError?.(ev as DailyEventObjectScreenShareError);
77+
},
78+
[onError]
79+
)
80+
);
5881

5982
const { screens } = useScreenSharesContext();
6083

src/types/Reconstruct.d.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* `Reconstruct` type utility.
3+
*
4+
* Given an object type `T`, a discriminator key `Key`, and a specific value `Value` for that key,
5+
* it reconstructs `T` such that the property denoted by `Key` is narrowed to just `Value`.
6+
*
7+
* Other properties of `T` remain unchanged.
8+
*
9+
* Example:
10+
*
11+
* If T = {
12+
* category: 'x' | 'y';
13+
* someProp: number;
14+
* }
15+
*
16+
* Key = 'category'
17+
* Value = 'x'
18+
*
19+
* Then, Reconstruct<T, Key, Value> will yield:
20+
*
21+
* {
22+
* category: 'x';
23+
* someProp: number;
24+
* }
25+
*
26+
*/
27+
export type Reconstruct<
28+
T,
29+
K extends keyof T = keyof T,
30+
V extends T[K] = T[K]
31+
> = {
32+
[P in keyof T]: P extends K ? V : T[P];
33+
};

0 commit comments

Comments
 (0)