Add StatContext to store global stat state
This commit is contained in:
parent
058d0cec0b
commit
002fef27a3
6 changed files with 82 additions and 41 deletions
|
@ -3,6 +3,7 @@ import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
|||
|
||||
import { getSettings } from 'soapbox/actions/settings';
|
||||
import DropdownMenu from 'soapbox/containers/dropdown_menu_container';
|
||||
import { useStatContext } from 'soapbox/contexts/stat-context';
|
||||
import ComposeButton from 'soapbox/features/ui/components/compose-button';
|
||||
import { useAppSelector, useOwnAccount } from 'soapbox/hooks';
|
||||
import { getFeatures } from 'soapbox/utils/features';
|
||||
|
@ -24,12 +25,12 @@ const messages = defineMessages({
|
|||
/** Desktop sidebar with links to different views in the app. */
|
||||
const SidebarNavigation = () => {
|
||||
const intl = useIntl();
|
||||
const { unreadChatsCount } = useStatContext();
|
||||
|
||||
const instance = useAppSelector((state) => state.instance);
|
||||
const settings = useAppSelector((state) => getSettings(state));
|
||||
const account = useOwnAccount();
|
||||
const notificationCount = useAppSelector((state) => state.notifications.get('unread'));
|
||||
const chatsCount = useAppSelector((state) => state.chats.items.reduce((acc, curr) => acc + Math.min(curr.unread || 0, 1), 0));
|
||||
const followRequestsCount = useAppSelector((state) => state.user_lists.follow_requests.items.count());
|
||||
const dashboardCount = useAppSelector((state) => state.admin.openReports.count() + state.admin.awaitingApproval.count());
|
||||
|
||||
|
@ -114,7 +115,7 @@ const SidebarNavigation = () => {
|
|||
<SidebarNavigationLink
|
||||
to='/chats'
|
||||
icon={require('@tabler/icons/mail.svg')}
|
||||
count={chatsCount}
|
||||
count={unreadChatsCount}
|
||||
text={<FormattedMessage id='navigation.direct_messages' defaultMessage='Messages' />}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -2,13 +2,15 @@ import React from 'react';
|
|||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import ThumbNavigationLink from 'soapbox/components/thumb_navigation-link';
|
||||
import { useStatContext } from 'soapbox/contexts/stat-context';
|
||||
import { useAppSelector, useOwnAccount } from 'soapbox/hooks';
|
||||
import { getFeatures } from 'soapbox/utils/features';
|
||||
|
||||
const ThumbNavigation: React.FC = (): JSX.Element => {
|
||||
const account = useOwnAccount();
|
||||
const { unreadChatsCount } = useStatContext();
|
||||
|
||||
const notificationCount = useAppSelector((state) => state.notifications.unread);
|
||||
const chatsCount = useAppSelector((state) => state.chats.items.reduce((acc, curr) => acc + Math.min(curr.unread || 0, 1), 0));
|
||||
const dashboardCount = useAppSelector((state) => state.admin.openReports.count() + state.admin.awaitingApproval.count());
|
||||
const features = getFeatures(useAppSelector((state) => state.instance));
|
||||
|
||||
|
@ -21,7 +23,7 @@ const ThumbNavigation: React.FC = (): JSX.Element => {
|
|||
text={<FormattedMessage id='navigation.direct_messages' defaultMessage='Messages' />}
|
||||
to='/chats'
|
||||
exact
|
||||
count={chatsCount}
|
||||
count={unreadChatsCount}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
29
app/soapbox/contexts/stat-context.tsx
Normal file
29
app/soapbox/contexts/stat-context.tsx
Normal file
|
@ -0,0 +1,29 @@
|
|||
import React, { createContext, useContext, useMemo, useState } from 'react';
|
||||
|
||||
type IStatContext = {
|
||||
unreadChatsCount: number,
|
||||
setUnreadChatsCount: React.Dispatch<React.SetStateAction<number>>
|
||||
}
|
||||
|
||||
const StatContext = createContext<any>({
|
||||
unreadChatsCount: 0,
|
||||
});
|
||||
|
||||
const StatProvider: React.FC = ({ children }) => {
|
||||
const [unreadChatsCount, setUnreadChatsCount] = useState<number>(0);
|
||||
|
||||
const value = useMemo(() => ({
|
||||
unreadChatsCount,
|
||||
setUnreadChatsCount,
|
||||
}), [unreadChatsCount]);
|
||||
|
||||
return (
|
||||
<StatContext.Provider value={value}>
|
||||
{children}
|
||||
</StatContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
const useStatContext = (): IStatContext => useContext(StatContext);
|
||||
|
||||
export { StatProvider, useStatContext };
|
|
@ -3,6 +3,7 @@ import React, { useState } from 'react';
|
|||
|
||||
import { Stack } from 'soapbox/components/ui';
|
||||
import { useChatContext } from 'soapbox/contexts/chat-context';
|
||||
import { useStatContext } from 'soapbox/contexts/stat-context';
|
||||
import { useDebounce, useFeatures } from 'soapbox/hooks';
|
||||
import { IChat, useChats } from 'soapbox/queries/chats';
|
||||
|
||||
|
@ -19,6 +20,7 @@ import Blankslate from './blankslate';
|
|||
const ChatPane = () => {
|
||||
const features = useFeatures();
|
||||
const debounce = useDebounce;
|
||||
const { unreadChatsCount } = useStatContext();
|
||||
|
||||
const [value, setValue] = useState<string>();
|
||||
const debouncedValue = debounce(value as string, 300);
|
||||
|
@ -26,8 +28,6 @@ const ChatPane = () => {
|
|||
const { chat, setChat, isOpen, isSearching, setSearching, toggleChatPane } = useChatContext();
|
||||
const { chatsQuery: { data: chats, isLoading } } = useChats(debouncedValue);
|
||||
|
||||
const unreadCount = sumBy(chats, (chat) => chat.unread);
|
||||
|
||||
const hasSearchValue = Number(debouncedValue?.length) > 0;
|
||||
|
||||
const handleClickChat = (chat: IChat) => {
|
||||
|
@ -89,7 +89,7 @@ const ChatPane = () => {
|
|||
<Pane isOpen={isOpen} index={0} main>
|
||||
<ChatPaneHeader
|
||||
title='Messages'
|
||||
unreadCount={unreadCount}
|
||||
unreadCount={unreadChatsCount}
|
||||
isOpen={isOpen}
|
||||
onToggle={toggleChatPane}
|
||||
secondaryAction={() => {
|
||||
|
|
|
@ -118,6 +118,7 @@ import { WrappedRoute } from './util/react_router_helpers';
|
|||
// Dummy import, to make sure that <Status /> ends up in the application bundle.
|
||||
// Without this it ends up in ~8 very commonly used bundles.
|
||||
import 'soapbox/components/status';
|
||||
import { StatProvider } from '../../contexts/stat-context';
|
||||
|
||||
const EmptyPage = HomePage;
|
||||
|
||||
|
@ -651,52 +652,54 @@ const UI: React.FC = ({ children }) => {
|
|||
};
|
||||
|
||||
return (
|
||||
<HotKeys keyMap={keyMap} handlers={me ? handlers : undefined} ref={setHotkeysRef} attach={window} focused>
|
||||
<div ref={node} style={style}>
|
||||
<BackgroundShapes />
|
||||
<StatProvider>
|
||||
<HotKeys keyMap={keyMap} handlers={me ? handlers : undefined} ref={setHotkeysRef} attach={window} focused>
|
||||
<div ref={node} style={style}>
|
||||
<BackgroundShapes />
|
||||
|
||||
<div className='z-10 flex flex-col'>
|
||||
<Navbar />
|
||||
<div className='z-10 flex flex-col'>
|
||||
<Navbar />
|
||||
|
||||
<Layout>
|
||||
<Layout.Sidebar>
|
||||
{!standalone && <SidebarNavigation />}
|
||||
</Layout.Sidebar>
|
||||
<Layout>
|
||||
<Layout.Sidebar>
|
||||
{!standalone && <SidebarNavigation />}
|
||||
</Layout.Sidebar>
|
||||
|
||||
<SwitchingColumnsArea>
|
||||
{children}
|
||||
</SwitchingColumnsArea>
|
||||
</Layout>
|
||||
<SwitchingColumnsArea>
|
||||
{children}
|
||||
</SwitchingColumnsArea>
|
||||
</Layout>
|
||||
|
||||
{me && floatingActionButton}
|
||||
{me && floatingActionButton}
|
||||
|
||||
<BundleContainer fetchComponent={UploadArea}>
|
||||
{Component => <Component active={draggingOver} onClose={closeUploadModal} />}
|
||||
</BundleContainer>
|
||||
<BundleContainer fetchComponent={UploadArea}>
|
||||
{Component => <Component active={draggingOver} onClose={closeUploadModal} />}
|
||||
</BundleContainer>
|
||||
|
||||
{me && (
|
||||
<BundleContainer fetchComponent={SidebarMenu}>
|
||||
{me && (
|
||||
<BundleContainer fetchComponent={SidebarMenu}>
|
||||
{Component => <Component />}
|
||||
</BundleContainer>
|
||||
)}
|
||||
|
||||
{me && features.chats && !mobile && (
|
||||
<BundleContainer fetchComponent={ChatWidget}>
|
||||
{Component => <Component />}
|
||||
</BundleContainer>
|
||||
)}
|
||||
<ThumbNavigation />
|
||||
|
||||
<BundleContainer fetchComponent={ProfileHoverCard}>
|
||||
{Component => <Component />}
|
||||
</BundleContainer>
|
||||
)}
|
||||
|
||||
{me && features.chats && !mobile && (
|
||||
<BundleContainer fetchComponent={ChatWidget}>
|
||||
<BundleContainer fetchComponent={StatusHoverCard}>
|
||||
{Component => <Component />}
|
||||
</BundleContainer>
|
||||
)}
|
||||
<ThumbNavigation />
|
||||
|
||||
<BundleContainer fetchComponent={ProfileHoverCard}>
|
||||
{Component => <Component />}
|
||||
</BundleContainer>
|
||||
|
||||
<BundleContainer fetchComponent={StatusHoverCard}>
|
||||
{Component => <Component />}
|
||||
</BundleContainer>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</HotKeys>
|
||||
</HotKeys>
|
||||
</StatProvider>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { useInfiniteQuery, useMutation, useQuery } from '@tanstack/react-query';
|
||||
import sumBy from 'lodash/sumBy';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { fetchRelationships } from 'soapbox/actions/accounts';
|
||||
|
@ -6,6 +7,7 @@ import snackbar from 'soapbox/actions/snackbar';
|
|||
import { getNextLink } from 'soapbox/api';
|
||||
import compareId from 'soapbox/compare_id';
|
||||
import { useChatContext } from 'soapbox/contexts/chat-context';
|
||||
import { useStatContext } from 'soapbox/contexts/stat-context';
|
||||
import { useApi, useAppDispatch, useFeatures } from 'soapbox/hooks';
|
||||
import { normalizeChatMessage } from 'soapbox/normalizers';
|
||||
import { flattenPages, PaginatedResult, updatePageItem } from 'soapbox/utils/queries';
|
||||
|
@ -101,6 +103,7 @@ const useChats = (search?: string) => {
|
|||
const api = useApi();
|
||||
const dispatch = useAppDispatch();
|
||||
const features = useFeatures();
|
||||
const { setUnreadChatsCount } = useStatContext();
|
||||
|
||||
const getChats = async (pageParam?: any): Promise<PaginatedResult<IChat>> => {
|
||||
const endpoint = features.chatsV2 ? '/api/v2/pleroma/chats' : '/api/v1/pleroma/chats';
|
||||
|
@ -116,6 +119,9 @@ const useChats = (search?: string) => {
|
|||
const link = getNextLink(response);
|
||||
const hasMore = !!link;
|
||||
|
||||
// TODO: change to response header
|
||||
setUnreadChatsCount(sumBy(data, (chat) => chat.unread));
|
||||
|
||||
// Set the relationships to these users in the redux store.
|
||||
dispatch(fetchRelationships(data.map((item) => item.account.id)));
|
||||
|
||||
|
|
Loading…
Reference in a new issue