import { Types } from "ably"; import { useCallback, useEffect, useState } from 'react'; import { assertConfiguration, ChannelParameters } from "../AblyReactHooks.js"; export type PresenceDataAndPresenceUpdateFunction = [ presenceData: PresenceMessage[], updateStatus: (messageOrPresenceObject: T) => void ]; export type OnPresenceMessageReceived = (presenceData: PresenceMessage) => void; export type UseStatePresenceUpdate = (presenceData: Types.PresenceMessage[]) => void; export function usePresence(channelNameOrNameAndOptions: ChannelParameters, messageOrPresenceObject?: T, onPresenceUpdated?: OnPresenceMessageReceived): PresenceDataAndPresenceUpdateFunction { const ably = typeof channelNameOrNameAndOptions === 'string' ? assertConfiguration() : (channelNameOrNameAndOptions.realtime || assertConfiguration()) const channelName = typeof channelNameOrNameAndOptions === 'string' ? channelNameOrNameAndOptions : channelNameOrNameAndOptions.channelName; const channel = typeof channelNameOrNameAndOptions === 'string' ? ably.channels.get(channelName) : ably.channels.get(channelName, channelNameOrNameAndOptions.options); const subscribeOnly = typeof channelNameOrNameAndOptions === 'string' ? false : channelNameOrNameAndOptions.subscribeOnly; const [presenceData, updatePresenceData] = useState([]) as [Array>, UseStatePresenceUpdate]; const updatePresence = async (message?: Types.PresenceMessage) => { const snapshot = await channel.presence.get(); updatePresenceData(snapshot); onPresenceUpdated?.call(this, message); } const onMount = async () => { channel.presence.subscribe('enter', updatePresence); channel.presence.subscribe('leave', updatePresence); channel.presence.subscribe('update', updatePresence); if (!subscribeOnly) { await channel.presence.enter(messageOrPresenceObject); } const snapshot = await channel.presence.get(); updatePresenceData(snapshot); } const onUnmount = () => { if (channel.state == 'attached') { if (!subscribeOnly) { channel.presence.leave(); } } channel.presence.unsubscribe('enter'); channel.presence.unsubscribe('leave'); channel.presence.unsubscribe('update'); } const useEffectHook = () => { onMount(); return () => { onUnmount(); }; }; useEffect(useEffectHook, []); const updateStatus = useCallback((messageOrPresenceObject: T) => { if (!subscribeOnly) { channel.presence.update(messageOrPresenceObject); } else { throw new Error("updateStatus can not be called while using the hook in subscribeOnly mode"); } }, [channel]); return [presenceData, updateStatus]; } interface PresenceMessage { action: Types.PresenceAction; clientId: string; connectionId: string; data: T; encoding: string; id: string; timestamp: number; }