import { useCallback, useState } from 'react' type QueueItem = { id: string } type EffectQueueState = { active?: T pending: T[] } export function enqueueEffect( state: EffectQueueState, effect: T, capacity: number, ): EffectQueueState { if (state.active?.id === effect.id || state.pending.some(item => item.id === effect.id)) { return state } if (!state.active) return { active: effect, pending: state.pending } const boundedCapacity = Number.isFinite(capacity) ? Math.max(1, Math.floor(capacity)) : 1 if (state.pending.length >= boundedCapacity) return state return { ...state, pending: [...state.pending, effect] } } export function completeEffect( state: EffectQueueState, activeId: string, ): EffectQueueState { if (state.active?.id !== activeId) return state const [active, ...pending] = state.pending return { active, pending } } export function useEffectQueue() { const [state, setState] = useState>({ pending: [] }) const enqueue = useCallback((effect: T, capacity: number) => { setState(current => enqueueEffect(current, effect, capacity)) }, []) const complete = useCallback((activeId: string) => { setState(current => completeEffect(current, activeId)) }, []) return { active: state.active, pendingCount: state.pending.length, enqueue, complete } }