UNPKG

@ably/chat

Version:

Ably Chat is a set of purpose-built APIs for a host of chat features enabling you to create 1:1, 1:Many, Many:1 and Many:Many chat rooms for any scale. It is designed to meet a wide range of chat use cases, such as livestreams, in-game communication, cust

138 lines (123 loc) 4.77 kB
import { useEffect, useState } from 'react'; import { OccupancyListener } from '../../core/occupancy.js'; import { wrapRoomPromise } from '../helper/room-promise.js'; import { ChatStatusResponse } from '../types/chat-status-response.js'; import { Listenable } from '../types/listenable.js'; import { StatusParams } from '../types/status-params.js'; import { useEventListenerRef } from './internal/use-event-listener-ref.js'; import { useRoomLogger } from './internal/use-logger.js'; import { useRoomContext } from './internal/use-room-context.js'; import { useRoomStatus } from './internal/use-room-status.js'; import { useChatConnection } from './use-chat-connection.js'; /** * The options for the {@link useOccupancy} hook. */ export interface UseOccupancyParams extends StatusParams, Listenable<OccupancyListener> { /** * A listener that will be called whenever an occupancy event is received. * The listener is removed when the component unmounts. */ listener?: OccupancyListener; } /** * The response type from the {@link useOccupancy} hook. */ export interface UseOccupancyResponse extends ChatStatusResponse { /** * The current number of users connected to the room, kept up to date by the hook. */ readonly connections: number; /** * The current number of users present in the room, kept up to date by the hook. */ readonly presenceMembers: number; } /** * A hook that provides access to the rooms occupancy information. * It will use the instance belonging to the nearest {@link ChatRoomProvider} in the component tree. * @param params - Allows the registering of optional callbacks. * @returns UseOccupancyResponse */ export const useOccupancy = (params?: UseOccupancyParams): UseOccupancyResponse => { const { currentStatus: connectionStatus, error: connectionError } = useChatConnection({ onStatusChange: params?.onConnectionStatusChange, }); const context = useRoomContext('useOccupancy'); const { status: roomStatus, error: roomError } = useRoomStatus(params); const logger = useRoomLogger(); logger.trace('useOccupancy();', { params }); const [occupancyMetrics, setOccupancyMetrics] = useState<{ connections: number; presenceMembers: number }>({ connections: 0, presenceMembers: 0, }); // create stable references for the listeners const listenerRef = useEventListenerRef(params?.listener); const onDiscontinuityRef = useEventListenerRef(params?.onDiscontinuity); // if provided, subscribes the user provided discontinuity listener useEffect(() => { if (!onDiscontinuityRef) return; return wrapRoomPromise( context.room, (room) => { logger.debug('useOccupancy(); applying onDiscontinuity listener'); const { off } = room.onDiscontinuity(onDiscontinuityRef); return () => { logger.debug('useOccupancy(); removing onDiscontinuity listener'); off(); }; }, logger, ).unmount(); }, [context, onDiscontinuityRef, logger]); // subscribe to occupancy events internally, to update the state metrics useEffect(() => { const roomPromise = wrapRoomPromise( context.room, (room) => { logger.debug('useOccupancy(); applying internal listener'); // Set the initial metrics from current(), or 0 if not available const currentOccupancy = room.occupancy.current(); setOccupancyMetrics({ connections: currentOccupancy?.connections ?? 0, presenceMembers: currentOccupancy?.presenceMembers ?? 0, }); const { unsubscribe } = room.occupancy.subscribe((occupancyEvent) => { setOccupancyMetrics({ connections: occupancyEvent.occupancy.connections, presenceMembers: occupancyEvent.occupancy.presenceMembers, }); }); return () => { logger.debug('useOccupancy(); cleaning up internal listener'); unsubscribe(); }; }, logger, ); return roomPromise.unmount(); }, [context, logger]); // if provided, subscribes the user provided listener to occupancy events useEffect(() => { if (!listenerRef) return; return wrapRoomPromise( context.room, (room) => { logger.debug('useOccupancy(); applying listener'); const { unsubscribe } = room.occupancy.subscribe(listenerRef); return () => { logger.debug('useOccupancy(); cleaning up listener'); unsubscribe(); }; }, logger, ).unmount(); }, [listenerRef, context, logger]); return { connectionStatus, connectionError, roomStatus, roomError, connections: occupancyMetrics.connections, presenceMembers: occupancyMetrics.presenceMembers, }; };