Files
glchat/web/src/components/chat/TypingIndicator.tsx
T

49 lines
1.5 KiB
TypeScript
Raw Normal View History

import { useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import type { AuthorDirectory } from '@/components/chat/useAuthorDirectory';
import { useMessagesStore, type TypingEntry } from '@/stores/messages';
interface TypingIndicatorProps {
channelId: string;
typing: TypingEntry[];
authors: AuthorDirectory;
}
/** Как часто проверяем, не погасли ли события `TYPING_START`. */
const PRUNE_INTERVAL_MS = 1000;
/**
* Строка «печатает…» под лентой. Живёт 6 секунд с последнего события
* `TYPING_START` (событие приходит раз в ~3 с, пока пользователь пишет).
*/
export function TypingIndicator({ channelId, typing, authors }: TypingIndicatorProps) {
const { t } = useTranslation();
useEffect(() => {
if (typing.length === 0) {
return;
}
const timer = window.setInterval(() => {
useMessagesStore.getState().pruneTyping();
}, PRUNE_INTERVAL_MS);
return () => {
window.clearInterval(timer);
};
}, [typing.length, channelId]);
if (typing.length === 0) {
return null;
}
const names = typing
.map((entry) => authors.resolve(entry.user_id).name)
.filter((name) => name !== '');
return (
<p role="status" data-testid="typing-indicator" className="px-4 pb-1 text-xs text-fg-muted">
{t('chat.typing', { count: names.length, names: names.join(', ') })}
</p>
);
}