diff --git a/src/components/MessageInput/hooks/__tests__/useCooldownTimer.test.js b/src/components/MessageInput/hooks/__tests__/useCooldownTimer.test.js new file mode 100644 index 0000000000..89a5d0fc27 --- /dev/null +++ b/src/components/MessageInput/hooks/__tests__/useCooldownTimer.test.js @@ -0,0 +1,58 @@ +import React from 'react'; +import { renderHook } from '@testing-library/react-hooks'; + +import { useCooldownTimer } from '../useCooldownTimer'; + +import { ChannelStateProvider, ChatProvider } from '../../../../context'; +import { getTestClient } from '../../../../mock-builders'; + +async function renderUseCooldownTimerHook({ channel, chatContext }) { + const client = await getTestClient(); + + const wrapper = ({ children }) => ( + + {children} + + ); + return renderHook(useCooldownTimer, { wrapper }); +} + +const cid = 'cid'; +const cooldown = 30; +describe('useCooldownTimer', () => { + it('should set remaining cooldown time to if no channel.cooldown', async () => { + const channel = { cid }; + const chatContext = { latestMessageDatesByChannels: {} }; + const { result } = await renderUseCooldownTimerHook({ channel, chatContext }); + expect(result.current.cooldownRemaining).toBe(0); + }); + it('should set remaining cooldown time to 0 if skip-slow-mode is among own_capabilities', async () => { + const channel = { cid, data: { cooldown, own_capabilities: ['skip-slow-mode'] } }; + const chatContext = { latestMessageDatesByChannels: { cid: new Date() } }; + const { result } = await renderUseCooldownTimerHook({ channel, chatContext }); + expect(result.current.cooldownRemaining).toBe(0); + }); + it('should set remaining cooldown time to 0 if no previous messages sent', async () => { + const channel = { cid, data: { cooldown } }; + const chatContext = { latestMessageDatesByChannels: {} }; + const { result } = await renderUseCooldownTimerHook({ channel, chatContext }); + expect(result.current.cooldownRemaining).toBe(0); + }); + it('should set remaining cooldown time to 0 if previous messages sent earlier than channel.cooldown', async () => { + const channel = { cid, data: { cooldown } }; + const chatContext = { latestMessageDatesByChannels: { cid: new Date('1970-1-1') } }; + const { result } = await renderUseCooldownTimerHook({ channel, chatContext }); + expect(result.current.cooldownRemaining).toBe(0); + }); + it('should set remaining cooldown time to time left from previous messages sent', async () => { + const channel = { cid, data: { cooldown } }; + const lastSentSecondsAgo = 5; + const chatContext = { + latestMessageDatesByChannels: { + cid: new Date(new Date().getTime() - lastSentSecondsAgo * 1000), + }, + }; + const { result } = await renderUseCooldownTimerHook({ channel, chatContext }); + expect(result.current.cooldownRemaining).toBe(cooldown - lastSentSecondsAgo); + }); +}); diff --git a/src/components/MessageInput/hooks/useCooldownTimer.tsx b/src/components/MessageInput/hooks/useCooldownTimer.tsx index 388f8a7ae2..551c3f9d2f 100644 --- a/src/components/MessageInput/hooks/useCooldownTimer.tsx +++ b/src/components/MessageInput/hooks/useCooldownTimer.tsx @@ -1,10 +1,8 @@ import React, { useEffect, useMemo, useState } from 'react'; - -import { useChatContext } from '../../../context/ChatContext'; -import { useChannelStateContext } from '../../../context/ChannelStateContext'; - import type { ChannelResponse } from 'stream-chat'; +import { useChannelStateContext, useChatContext } from '../../../context'; + import type { DefaultStreamChatGenerics } from '../../../types/types'; export type CooldownTimerState = { @@ -16,15 +14,16 @@ export type CooldownTimerState = { export const useCooldownTimer = < StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics >(): CooldownTimerState => { - const { latestMessageDatesByChannels } = useChatContext('useCooldownTimer'); + const { client, latestMessageDatesByChannels } = useChatContext( + 'useCooldownTimer', + ); const { channel, messages = [] } = useChannelStateContext('useCooldownTimer'); - const { client } = useChatContext('useCooldownTimer'); const [cooldownRemaining, setCooldownRemaining] = useState(); - const { cooldown: cooldownInterval, own_capabilities } = (channel.data || + const { cooldown: cooldownInterval = 0, own_capabilities } = (channel.data || {}) as ChannelResponse; - const skipCooldown = !own_capabilities?.includes('slow-mode'); + const skipCooldown = own_capabilities?.includes('skip-slow-mode'); const ownLatestMessageDate = useMemo( () => @@ -36,17 +35,19 @@ export const useCooldownTimer = < ) as Date; useEffect(() => { - if (skipCooldown || !cooldownInterval || !ownLatestMessageDate) return; - - const remainingCooldown = Math.round( - cooldownInterval - (new Date().getTime() - ownLatestMessageDate.getTime()) / 1000, + const timeSinceOwnLastMessage = ownLatestMessageDate + ? (new Date().getTime() - ownLatestMessageDate.getTime()) / 1000 + : undefined; + + setCooldownRemaining( + !skipCooldown && timeSinceOwnLastMessage && cooldownInterval > timeSinceOwnLastMessage + ? Math.round(cooldownInterval - timeSinceOwnLastMessage) + : 0, ); - - if (remainingCooldown > 0) setCooldownRemaining(remainingCooldown); }, [cooldownInterval, ownLatestMessageDate, skipCooldown]); return { - cooldownInterval: cooldownInterval ?? 0, + cooldownInterval, cooldownRemaining, setCooldownRemaining, };