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,
};