-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathuse-room-status.ts
120 lines (104 loc) · 3.49 KB
/
use-room-status.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import { Room, RoomStatus, RoomStatusChange } from '@ably/chat';
import * as Ably from 'ably';
import { useEffect, useState } from 'react';
import { useLogger } from '../hooks/use-logger.js';
import { wrapRoomPromise } from './room-promise.js';
import { useEventListenerRef } from './use-event-listener-ref.js';
import { useRoomContext } from './use-room-context.js';
/**
* The response object for the useRoomStatus hook.
*/
export interface UseRoomStatusResponse {
/**
* The current status of the room.
*/
readonly status: RoomStatus;
/**
* The error that caused the room to transition to an errored state.
*/
readonly error?: Ably.ErrorInfo;
}
/**
* The parameters for the useRoomStatus hook.
*/
export interface UseRoomStatusParams {
/**
* A listener for room status changes.
*/
onRoomStatusChange?: (change: RoomStatusChange) => void;
}
/**
* A hook that returns the current status of the room, and listens for changes to the room status.
*
* @internal
* @param params An optional user-provided listener for room status changes.
* @returns The current status of the room, and an error if the room is in an errored state.
*/
export const useRoomStatus = (params?: UseRoomStatusParams): UseRoomStatusResponse => {
const context = useRoomContext('useRoomStatus');
const [status, setStatus] = useState<RoomStatus>(RoomStatus.Initializing);
const [error, setError] = useState<Ably.ErrorInfo | undefined>();
const logger = useLogger();
// create stable references for the listeners and register the user-provided callbacks
const onRoomStatusChangeRef = useEventListenerRef(params?.onRoomStatusChange);
// create an internal listener to update the status
useEffect(() => {
const roomPromise = wrapRoomPromise(
context.room,
(room: Room) => {
logger.debug('useRoomStatus(); subscribing internal listener');
// Set instantaneous values
setStatus(room.status);
setError(room.error);
// Add the subscription
const { off } = room.onStatusChange((change) => {
logger.debug('useRoomStatus(); status change', change);
setStatus(change.current);
setError(change.error);
});
return () => {
logger.debug('useRoomStatus(); unsubscribing internal listener');
off();
};
},
logger,
context.roomId,
);
return roomPromise.unmount();
}, [context, logger]);
useEffect(() => {
const roomPromise = wrapRoomPromise(
context.room,
(room: Room) => {
let off: (() => void) | undefined;
if (onRoomStatusChangeRef) {
logger.debug('useRoomStatus(); subscribing to status changes');
off = room.onStatusChange(onRoomStatusChangeRef).off;
}
logger.debug('useRoomStatus(); setting initial status', { status: room.status });
if (onRoomStatusChangeRef) {
logger.debug('useRoomStatus(); sending initial status event');
onRoomStatusChangeRef({
current: room.status,
previous: RoomStatus.Initializing,
error: room.error,
});
}
return () => {
logger.debug('useRoomStatus(); unmounting');
if (off) {
logger.debug('useRoomStatus(); unsubscribing from status changes');
off();
}
};
},
logger,
context.roomId,
);
return roomPromise.unmount();
}, [context, logger, onRoomStatusChangeRef]);
return {
status,
error,
};
};