import { useCallback, useEffect, useState } from 'react'; import { useAdapter } from '../provider'; import type { ChannelSummary, CreateChannelInput } from '../types'; export interface ChannelsState { /** Discoverable channels (public + private-I'm-in), each flagged `joined`. */ browsable: ChannelSummary[]; loading: boolean; error: string | null; /** Whether the adapter implements channels at all — drives showing/hiding the channels UI. */ supported: boolean; refetch: () => void; create: (input: CreateChannelInput) => Promise; join: (threadId: string) => Promise; leave: (threadId: string) => Promise; } export function useChannels(): ChannelsState { const adapter = useAdapter(); const supported = typeof adapter.browseChannels === 'function'; const [browsable, setBrowsable] = useState([]); const [loading, setLoading] = useState(supported); const [error, setError] = useState(null); const [nonce, setNonce] = useState(0); useEffect(() => { if (!adapter.browseChannels) { setLoading(false); return; } let alive = true; setLoading(true); adapter .browseChannels() .then((list) => { if (!alive) return; setBrowsable(list); setError(null); }) .catch((e: unknown) => { if (!alive) return; setError(e instanceof Error ? e.message : String(e)); setBrowsable([]); }) .finally(() => { if (alive) setLoading(false); }); return () => { alive = false; }; }, [adapter, nonce]); const refetch = useCallback(() => setNonce((n) => n + 1), []); const create = useCallback( async (input: CreateChannelInput) => { if (!adapter.createChannel) throw new Error('channels not supported by this adapter'); const { threadId } = await adapter.createChannel(input); setNonce((n) => n + 1); return threadId; }, [adapter], ); const join = useCallback( async (threadId: string) => { if (!adapter.joinChannel) throw new Error('channels not supported by this adapter'); await adapter.joinChannel(threadId); setNonce((n) => n + 1); }, [adapter], ); const leave = useCallback( async (threadId: string) => { if (!adapter.leaveChannel) throw new Error('channels not supported by this adapter'); await adapter.leaveChannel(threadId); setNonce((n) => n + 1); }, [adapter], ); return { browsable, loading, error, supported, refetch, create, join, leave }; }