import { MarkMentionsReadComposer, RequestMentionsComposer } from '@nitrots/nitro-renderer'; import { FC, useCallback, useEffect, useMemo, useState } from 'react'; import { FaSearch, FaSync } from 'react-icons/fa'; import { getMentionDateGroup, IMentionEntry, LocalizeText, MentionDateGroup, MentionType, SendMessageComposer } from '../../api'; import { Button, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../common'; import { useMentionActions, useMentionsSnapshot } from '../../hooks'; import { markAllRead } from '../../hooks/mentions/mentionsStore'; import { useUserDataSnapshot } from '../../hooks/session/useSessionSnapshots'; import { MentionRowView } from './MentionRowView'; interface MentionsViewProps { onClose: () => void; } type MentionFilter = 'all' | 'unread' | 'direct' | 'room'; const FILTERS: ReadonlyArray<{ key: MentionFilter; label: string }> = [ { key: 'all', label: 'mentions.filter.all' }, { key: 'unread', label: 'mentions.filter.unread' }, { key: 'direct', label: 'mentions.filter.direct' }, { key: 'room', label: 'mentions.filter.room' } ]; const GROUP_ORDER: ReadonlyArray = [ 'today', 'yesterday', 'older' ]; const GROUP_LABEL: Record = { today: 'mentions.group.today', yesterday: 'mentions.group.yesterday', older: 'mentions.group.older' }; const matchesFilter = (mention: IMentionEntry, filter: MentionFilter): boolean => { switch(filter) { case 'unread': return !mention.read; case 'direct': return mention.mentionType === MentionType.DIRECT; case 'room': return mention.mentionType === MentionType.ROOM; default: return true; } }; const matchesQuery = (mention: IMentionEntry, query: string): boolean => { if(!query) return true; const q = query.toLowerCase(); return ((mention.senderUsername || '').toLowerCase().includes(q) || (mention.roomName || '').toLowerCase().includes(q) || (mention.message || '').toLowerCase().includes(q)); }; export const MentionsView: FC = props => { const { onClose } = props; const { mentions, unreadCount } = useMentionsSnapshot(); const { userName: ownUsername = '' } = useUserDataSnapshot(); const { open, goto, remove } = useMentionActions(); const [ filter, setFilter ] = useState('all'); const [ query, setQuery ] = useState(''); // Re-request from the server: once on open, and on the manual refresh button. const refresh = useCallback(() => SendMessageComposer(new RequestMentionsComposer()), []); useEffect(() => { refresh(); }, [ refresh ]); const onMarkAll = useCallback(() => { markAllRead(); SendMessageComposer(new MarkMentionsReadComposer(0, 0)); }, []); const groups = useMemo(() => { const buckets: Record = { today: [], yesterday: [], older: [] }; for(const mention of mentions) { if(!matchesFilter(mention, filter)) continue; if(!matchesQuery(mention, query)) continue; buckets[getMentionDateGroup(mention.timestamp)].push(mention); } return GROUP_ORDER .map(key => ({ key, items: buckets[key] })) .filter(group => group.items.length > 0); }, [ mentions, filter, query ]); const hasAny = groups.length > 0; const title = `${ LocalizeText('mentions.window.title') }${ (unreadCount > 0) ? ` (${ unreadCount })` : '' }`; return (
setQuery(event.target.value) } />
{ FILTERS.map(({ key, label }) => { const active = (filter === key); const showCount = ((key === 'unread') && (unreadCount > 0)); return ( ); }) }
{ !hasAny &&
@ { LocalizeText('mentions.window.empty') }
} { hasAny && groups.map(group => (
{ LocalizeText(GROUP_LABEL[group.key]) }
{ group.items.map(mention => ( )) }
)) }
{ (unreadCount > 0) && }
); };