Move StatProvider above UI, increment chats unread counter from streaming events

environments/review-chats-g56n7m/deployments/1667
Alex Gleason 2022-12-07 00:45:10 -06:00
rodzic d811500812
commit fbd2471dc6
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 7211D1F99744FBB7
5 zmienionych plików z 74 dodań i 53 usunięć

Wyświetl plik

@ -2,7 +2,7 @@ import { getSettings } from 'soapbox/actions/settings';
import messages from 'soapbox/locales/messages'; import messages from 'soapbox/locales/messages';
import { ChatKeys, IChat, isLastMessage } from 'soapbox/queries/chats'; import { ChatKeys, IChat, isLastMessage } from 'soapbox/queries/chats';
import { queryClient } from 'soapbox/queries/client'; import { queryClient } from 'soapbox/queries/client';
import { updateChatListItem } from 'soapbox/utils/chats'; import { getUnreadChatsCount, updateChatListItem } from 'soapbox/utils/chats';
import { removePageItem } from 'soapbox/utils/queries'; import { removePageItem } from 'soapbox/utils/queries';
import { play, soundCache } from 'soapbox/utils/sounds'; import { play, soundCache } from 'soapbox/utils/sounds';
@ -27,6 +27,7 @@ import {
processTimelineUpdate, processTimelineUpdate,
} from './timelines'; } from './timelines';
import type { IStatContext } from 'soapbox/contexts/stat-context';
import type { AppDispatch, RootState } from 'soapbox/store'; import type { AppDispatch, RootState } from 'soapbox/store';
import type { APIEntity, Chat } from 'soapbox/types/entities'; import type { APIEntity, Chat } from 'soapbox/types/entities';
@ -79,11 +80,16 @@ const updateChatQuery = (chat: IChat) => {
queryClient.setQueryData<Chat>(ChatKeys.chat(chat.id), newChat as any); queryClient.setQueryData<Chat>(ChatKeys.chat(chat.id), newChat as any);
}; };
interface StreamOpts {
statContext?: IStatContext,
}
const connectTimelineStream = ( const connectTimelineStream = (
timelineId: string, timelineId: string,
path: string, path: string,
pollingRefresh: ((dispatch: AppDispatch, done?: () => void) => void) | null = null, pollingRefresh: ((dispatch: AppDispatch, done?: () => void) => void) | null = null,
accept: ((status: APIEntity) => boolean) | null = null, accept: ((status: APIEntity) => boolean) | null = null,
opts?: StreamOpts,
) => connectStream(path, pollingRefresh, (dispatch: AppDispatch, getState: () => RootState) => { ) => connectStream(path, pollingRefresh, (dispatch: AppDispatch, getState: () => RootState) => {
const locale = getLocale(getState()); const locale = getLocale(getState());
@ -145,6 +151,9 @@ const connectTimelineStream = (
if (settings.getIn(['chats', 'sound'])) { if (settings.getIn(['chats', 'sound'])) {
play(soundCache.chat); play(soundCache.chat);
} }
// Increment unread counter
opts?.statContext?.setUnreadChatsCount(getUnreadChatsCount());
} }
}); });
break; break;
@ -186,8 +195,8 @@ const refreshHomeTimelineAndNotification = (dispatch: AppDispatch, done?: () =>
dispatch(expandNotifications({}, () => dispatch(expandNotifications({}, () =>
dispatch(fetchAnnouncements(done)))))); dispatch(fetchAnnouncements(done))))));
const connectUserStream = () => const connectUserStream = (opts?: StreamOpts) =>
connectTimelineStream('home', 'user', refreshHomeTimelineAndNotification); connectTimelineStream('home', 'user', refreshHomeTimelineAndNotification, null, opts);
const connectCommunityStream = ({ onlyMedia }: Record<string, any> = {}) => const connectCommunityStream = ({ onlyMedia }: Record<string, any> = {}) =>
connectTimelineStream(`community${onlyMedia ? ':media' : ''}`, `public:local${onlyMedia ? ':media' : ''}`); connectTimelineStream(`community${onlyMedia ? ':media' : ''}`, `public:local${onlyMedia ? ':media' : ''}`);

Wyświetl plik

@ -17,6 +17,7 @@ import * as BuildConfig from 'soapbox/build-config';
import GdprBanner from 'soapbox/components/gdpr-banner'; import GdprBanner from 'soapbox/components/gdpr-banner';
import Helmet from 'soapbox/components/helmet'; import Helmet from 'soapbox/components/helmet';
import LoadingScreen from 'soapbox/components/loading-screen'; import LoadingScreen from 'soapbox/components/loading-screen';
import { StatProvider } from 'soapbox/contexts/stat-context';
import AuthLayout from 'soapbox/features/auth-layout'; import AuthLayout from 'soapbox/features/auth-layout';
import EmbeddedStatus from 'soapbox/features/embedded-status'; import EmbeddedStatus from 'soapbox/features/embedded-status';
import PublicLayout from 'soapbox/features/public-layout'; import PublicLayout from 'soapbox/features/public-layout';
@ -296,11 +297,13 @@ const Soapbox: React.FC = () => {
return ( return (
<Provider store={store}> <Provider store={store}>
<QueryClientProvider client={queryClient}> <QueryClientProvider client={queryClient}>
<SoapboxHead> <StatProvider>
<SoapboxLoad> <SoapboxHead>
<SoapboxMount /> <SoapboxLoad>
</SoapboxLoad> <SoapboxMount />
</SoapboxHead> </SoapboxLoad>
</SoapboxHead>
</StatProvider>
</QueryClientProvider> </QueryClientProvider>
</Provider> </Provider>
); );

Wyświetl plik

@ -26,4 +26,4 @@ const StatProvider: React.FC = ({ children }) => {
const useStatContext = (): IStatContext => useContext(StatContext); const useStatContext = (): IStatContext => useContext(StatContext);
export { StatProvider, useStatContext }; export { StatProvider, useStatContext, IStatContext };

Wyświetl plik

@ -24,7 +24,7 @@ import Icon from 'soapbox/components/icon';
import SidebarNavigation from 'soapbox/components/sidebar-navigation'; import SidebarNavigation from 'soapbox/components/sidebar-navigation';
import ThumbNavigation from 'soapbox/components/thumb-navigation'; import ThumbNavigation from 'soapbox/components/thumb-navigation';
import { Layout } from 'soapbox/components/ui'; import { Layout } from 'soapbox/components/ui';
import { StatProvider } from 'soapbox/contexts/stat-context'; import { useStatContext } from 'soapbox/contexts/stat-context';
import { useAppDispatch, useAppSelector, useOwnAccount, useSoapboxConfig, useFeatures, useInstance } from 'soapbox/hooks'; import { useAppDispatch, useAppSelector, useOwnAccount, useSoapboxConfig, useFeatures, useInstance } from 'soapbox/hooks';
import AdminPage from 'soapbox/pages/admin-page'; import AdminPage from 'soapbox/pages/admin-page';
import ChatsPage from 'soapbox/pages/chats-page'; import ChatsPage from 'soapbox/pages/chats-page';
@ -323,6 +323,7 @@ const UI: React.FC = ({ children }) => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { data: pendingPolicy } = usePendingPolicy(); const { data: pendingPolicy } = usePendingPolicy();
const instance = useInstance(); const instance = useInstance();
const statContext = useStatContext();
const [draggingOver, setDraggingOver] = useState<boolean>(false); const [draggingOver, setDraggingOver] = useState<boolean>(false);
@ -420,7 +421,7 @@ const UI: React.FC = ({ children }) => {
const connectStreaming = () => { const connectStreaming = () => {
if (!disconnect.current && accessToken && streamingUrl) { if (!disconnect.current && accessToken && streamingUrl) {
disconnect.current = dispatch(connectUserStream()); disconnect.current = dispatch(connectUserStream({ statContext }));
} }
}; };
@ -642,58 +643,56 @@ const UI: React.FC = ({ children }) => {
}; };
return ( return (
<StatProvider> <HotKeys keyMap={keyMap} handlers={me ? handlers : undefined} ref={setHotkeysRef} attach={window} focused>
<HotKeys keyMap={keyMap} handlers={me ? handlers : undefined} ref={setHotkeysRef} attach={window} focused> <div ref={node} style={style}>
<div ref={node} style={style}> <BackgroundShapes />
<BackgroundShapes />
<div className='z-10 flex flex-col'> <div className='z-10 flex flex-col'>
<Navbar /> <Navbar />
<Layout> <Layout>
<Layout.Sidebar> <Layout.Sidebar>
{!standalone && <SidebarNavigation />} {!standalone && <SidebarNavigation />}
</Layout.Sidebar> </Layout.Sidebar>
<SwitchingColumnsArea> <SwitchingColumnsArea>
{children} {children}
</SwitchingColumnsArea> </SwitchingColumnsArea>
</Layout> </Layout>
{me && floatingActionButton} {me && floatingActionButton}
<BundleContainer fetchComponent={UploadArea}> <BundleContainer fetchComponent={UploadArea}>
{Component => <Component active={draggingOver} onClose={closeUploadModal} />} {Component => <Component active={draggingOver} onClose={closeUploadModal} />}
</BundleContainer> </BundleContainer>
{me && ( {me && (
<BundleContainer fetchComponent={SidebarMenu}> <BundleContainer fetchComponent={SidebarMenu}>
{Component => <Component />}
</BundleContainer>
)}
{me && features.chats && (
<BundleContainer fetchComponent={ChatWidget}>
{Component => (
<div className='hidden xl:block'>
<Component />
</div>
)}
</BundleContainer>
)}
<ThumbNavigation />
<BundleContainer fetchComponent={ProfileHoverCard}>
{Component => <Component />} {Component => <Component />}
</BundleContainer> </BundleContainer>
)}
<BundleContainer fetchComponent={StatusHoverCard}> {me && features.chats && (
{Component => <Component />} <BundleContainer fetchComponent={ChatWidget}>
{Component => (
<div className='hidden xl:block'>
<Component />
</div>
)}
</BundleContainer> </BundleContainer>
</div> )}
<ThumbNavigation />
<BundleContainer fetchComponent={ProfileHoverCard}>
{Component => <Component />}
</BundleContainer>
<BundleContainer fetchComponent={StatusHoverCard}>
{Component => <Component />}
</BundleContainer>
</div> </div>
</HotKeys> </div>
</StatProvider> </HotKeys>
); );
}; };

Wyświetl plik

@ -1,4 +1,5 @@
import { InfiniteData } from '@tanstack/react-query'; import { InfiniteData } from '@tanstack/react-query';
import sumBy from 'lodash/sumBy';
import { normalizeChatMessage } from 'soapbox/normalizers'; import { normalizeChatMessage } from 'soapbox/normalizers';
import { ChatKeys } from 'soapbox/queries/chats'; import { ChatKeys } from 'soapbox/queries/chats';
@ -71,4 +72,13 @@ const updateChatListItem = (newChat: ChatPayload) => {
} }
}; };
export { updateChatListItem }; /** Get unread chats count. */
const getUnreadChatsCount = (): number => {
const chats = flattenPages(
queryClient.getQueryData<InfiniteData<PaginatedResult<Chat>>>(ChatKeys.chatSearch()),
);
return sumBy(chats, chat => chat.unread);
};
export { updateChatListItem, getUnreadChatsCount };