Topics: Fix loading after refresh (#6967)
This commit is contained in:
parent
73b5ebeeba
commit
d7082efd93
@ -17,7 +17,7 @@ import {
|
||||
selectMonoforumChannel,
|
||||
selectPeer,
|
||||
selectTabState,
|
||||
selectTopics,
|
||||
selectTopicsInfo,
|
||||
selectUserStatus,
|
||||
} from '../../../global/selectors';
|
||||
import { selectAnimationLevel } from '../../../global/selectors/sharedState';
|
||||
@ -135,15 +135,16 @@ const ChatOrUserPicker = ({
|
||||
useInputFocusOnOpen(searchRef, isOpen && activeKey === CHAT_LIST_SLIDE, resetSearch);
|
||||
useInputFocusOnOpen(topicSearchRef, isOpen && activeKey === TOPIC_LIST_SLIDE);
|
||||
|
||||
const selectTopicsById = useCallback((global: GlobalState) => {
|
||||
const selectForumTopicsInfo = useCallback((global: GlobalState) => {
|
||||
if (!forumId) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return selectTopics(global, forumId);
|
||||
return selectTopicsInfo(global, forumId);
|
||||
}, [forumId]);
|
||||
|
||||
const forumTopicsById = useSelector(selectTopicsById);
|
||||
const topicsInfo = useSelector(selectForumTopicsInfo);
|
||||
const forumTopicsById = topicsInfo?.topicsById;
|
||||
|
||||
const [topicIds, topics] = useMemo(() => {
|
||||
const global = getGlobal();
|
||||
@ -194,7 +195,7 @@ const ChatOrUserPicker = ({
|
||||
const chatId = viewportIds[index === -1 ? 0 : index];
|
||||
const chat = chatsById[chatId];
|
||||
if (chat?.isForum) {
|
||||
if (!forumTopicsById) loadTopics({ chatId });
|
||||
if (!topicsInfo || topicsInfo.isCache) loadTopics({ chatId });
|
||||
setForumId(chatId);
|
||||
} else {
|
||||
onSelectChatOrUser(chatId);
|
||||
@ -218,7 +219,7 @@ const ChatOrUserPicker = ({
|
||||
const chatsById = getGlobal().chats.byId;
|
||||
const chat = chatsById?.[chatId];
|
||||
if (chat?.isForum) {
|
||||
if (!forumTopicsById) loadTopics({ chatId });
|
||||
if (!topicsInfo || topicsInfo.isCache) loadTopics({ chatId });
|
||||
setForumId(chatId);
|
||||
resetSearch();
|
||||
} else {
|
||||
|
||||
@ -18,7 +18,7 @@ import type {
|
||||
import type { ObserveFn } from '../../../hooks/useIntersectionObserver';
|
||||
import type { ChatAnimationTypes } from './hooks';
|
||||
import { MAIN_THREAD_ID } from '../../../api/types';
|
||||
import { StoryViewerOrigin } from '../../../types';
|
||||
import { StoryViewerOrigin, type TopicsInfo } from '../../../types';
|
||||
|
||||
import { ALL_FOLDER_ID, UNMUTE_TIMESTAMP } from '../../../config';
|
||||
import {
|
||||
@ -106,7 +106,7 @@ type StateProps = {
|
||||
chat?: ApiChat;
|
||||
monoforumChannel?: ApiChat;
|
||||
lastMessageStory?: ApiTypeStory;
|
||||
listedTopicIds?: number[];
|
||||
topicsInfo?: TopicsInfo;
|
||||
isMuted?: boolean;
|
||||
user?: ApiUser;
|
||||
userStatus?: ApiUserStatus;
|
||||
@ -139,7 +139,7 @@ const Chat: FC<OwnProps & StateProps> = ({
|
||||
shiftDiff,
|
||||
animationType,
|
||||
isPinned,
|
||||
listedTopicIds,
|
||||
topicsInfo,
|
||||
observeIntersection,
|
||||
chat,
|
||||
monoforumChannel,
|
||||
@ -204,6 +204,7 @@ const Chat: FC<OwnProps & StateProps> = ({
|
||||
|
||||
const { isForum, isForumAsMessages, isMonoforum } = chat || {};
|
||||
|
||||
const listedTopicIds = topicsInfo?.listedTopicIds;
|
||||
const shouldForceNonForumView = chat?.isBotForum && listedTopicIds && !listedTopicIds.length;
|
||||
|
||||
useEnsureMessage(isSavedDialog ? currentUserId : chatId, lastMessageId, lastMessage);
|
||||
@ -373,10 +374,10 @@ const Chat: FC<OwnProps & StateProps> = ({
|
||||
|
||||
// Load the forum topics to display unread count badge
|
||||
useEffect(() => {
|
||||
if (isIntersecting && isForum && isSynced && listedTopicIds === undefined) {
|
||||
if (isIntersecting && isForum && isSynced && (!topicsInfo || topicsInfo.isCache)) {
|
||||
loadTopics({ chatId });
|
||||
}
|
||||
}, [chatId, listedTopicIds, isSynced, isForum, isIntersecting]);
|
||||
}, [chatId, topicsInfo, isSynced, isForum, isIntersecting]);
|
||||
|
||||
const isOnline = user && userStatus && isUserOnline(user, userStatus);
|
||||
const { hasShownClass: isAvatarOnlineShown } = useShowTransitionDeprecated(isOnline);
|
||||
@ -598,7 +599,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
lastMessage,
|
||||
lastMessageId,
|
||||
currentUserId: global.currentUserId!,
|
||||
listedTopicIds: topicsInfo?.listedTopicIds,
|
||||
topicsInfo,
|
||||
isSynced: global.isSynced,
|
||||
lastMessageStory,
|
||||
isAccountFrozen,
|
||||
|
||||
@ -34,7 +34,6 @@ import { mapTruthyValues, mapValues } from '../../../../util/iteratees';
|
||||
|
||||
import useSelector from '../../../../hooks/data/useSelector';
|
||||
import useAppLayout from '../../../../hooks/useAppLayout';
|
||||
import useEffectWithPrevDeps from '../../../../hooks/useEffectWithPrevDeps';
|
||||
import useHistoryBack from '../../../../hooks/useHistoryBack';
|
||||
import useInfiniteScroll from '../../../../hooks/useInfiniteScroll';
|
||||
import { useIntersectionObserver, useOnIntersect } from '../../../../hooks/useIntersectionObserver';
|
||||
@ -97,13 +96,11 @@ const ForumPanel = ({
|
||||
const { isMobile } = useAppLayout();
|
||||
const chatId = chat?.id;
|
||||
|
||||
useEffectWithPrevDeps(([prevIsSynced]) => {
|
||||
if (!isSynced) return;
|
||||
const hasJustSynced = prevIsSynced === false;
|
||||
if (chatId && (hasJustSynced || !topicsInfo)) {
|
||||
loadTopics({ chatId, force: hasJustSynced });
|
||||
}
|
||||
}, [isSynced, chatId, topicsInfo]);
|
||||
useEffect(() => {
|
||||
if (!chatId || !isSynced) return;
|
||||
if (topicsInfo && !topicsInfo.isCache) return;
|
||||
loadTopics({ chatId });
|
||||
}, [chatId, topicsInfo, isSynced]);
|
||||
|
||||
const [isScrolled, setIsScrolled] = useState(false);
|
||||
const lang = useLang();
|
||||
|
||||
@ -2622,12 +2622,17 @@ addActionHandler('loadTopics', async (global, actions, payload): Promise<void> =
|
||||
if (!chat) return;
|
||||
|
||||
const topicsInfo = selectTopicsInfo(global, chatId);
|
||||
const shouldRefreshFromStart = force || topicsInfo?.isCache;
|
||||
|
||||
if (!force && topicsInfo?.listedTopicIds && topicsInfo.listedTopicIds.length === topicsInfo.totalCount) {
|
||||
if (
|
||||
!shouldRefreshFromStart
|
||||
&& topicsInfo?.listedTopicIds
|
||||
&& topicsInfo.listedTopicIds.length === topicsInfo.totalCount
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const offsetTopic = !force ? topicsInfo?.listedTopicIds?.reduce((acc, el) => {
|
||||
const offsetTopic = !shouldRefreshFromStart ? topicsInfo?.listedTopicIds?.reduce((acc, el) => {
|
||||
const topicThreadInfo = selectThreadInfo(global, chatId, el);
|
||||
const accTopicThreadInfo = selectThreadInfo(global, chatId, acc);
|
||||
if (!topicThreadInfo?.lastMessageId) return acc;
|
||||
@ -2649,12 +2654,22 @@ addActionHandler('loadTopics', async (global, actions, payload): Promise<void> =
|
||||
if (!result) return;
|
||||
|
||||
global = getGlobal();
|
||||
const updatedTopicsInfo = selectTopicsInfo(global, chatId);
|
||||
if (updatedTopicsInfo?.isCache) { // Reset local state
|
||||
global = updateTopicsInfo(global, chatId, {
|
||||
topicsById: {},
|
||||
listedTopicIds: [],
|
||||
orderedPinnedTopicIds: undefined,
|
||||
});
|
||||
}
|
||||
|
||||
global = addMessages(global, result.messages);
|
||||
result.topics.forEach((topic) => {
|
||||
global = updateTopicWithState(global, chatId, topic);
|
||||
});
|
||||
global = updateTopicsInfo(global, chatId, {
|
||||
totalCount: result.count,
|
||||
isCache: undefined,
|
||||
});
|
||||
global = updateListedTopicIds(global, chatId, result.topics.map((topicState) => topicState.topic.id));
|
||||
Object.entries(result.draftsById || {}).forEach(([threadId, draft]) => {
|
||||
|
||||
@ -5,7 +5,7 @@ import type {
|
||||
ApiAvailableReaction,
|
||||
ApiMessage,
|
||||
} from '../api/types';
|
||||
import type { MessageList, ThreadId } from '../types';
|
||||
import type { MessageList, ThreadId, TopicsInfo } from '../types';
|
||||
import type { ActionReturnType, GlobalState, SharedState } from './types';
|
||||
import { ApiMessageEntityTypes, MAIN_THREAD_ID } from '../api/types';
|
||||
|
||||
@ -649,10 +649,25 @@ function reduceChats<T extends GlobalState>(global: T): GlobalState['chats'] {
|
||||
all: pickTruthy(global.chats.lastMessageIds.all || {}, idsToSave),
|
||||
saved: global.chats.lastMessageIds.saved,
|
||||
},
|
||||
topicsInfoById: pickTruthy(global.chats.topicsInfoById, currentChatIds),
|
||||
topicsInfoById: reduceTopicsInfo(global.chats.topicsInfoById, currentChatIds),
|
||||
};
|
||||
}
|
||||
|
||||
function reduceTopicsInfo(
|
||||
topicsInfoById: Record<string, TopicsInfo>, chatIds: string[],
|
||||
): GlobalState['chats']['topicsInfoById'] {
|
||||
const topicsInfoToSave = pickTruthy(topicsInfoById, chatIds);
|
||||
|
||||
return Object.entries(topicsInfoToSave).reduce((acc, [chatId, topicsInfo]) => {
|
||||
acc[chatId] = {
|
||||
...topicsInfo,
|
||||
isCache: true,
|
||||
};
|
||||
|
||||
return acc;
|
||||
}, {} as GlobalState['chats']['topicsInfoById']);
|
||||
}
|
||||
|
||||
function getTopPeerIds<T extends GlobalState>(global: T) {
|
||||
return unique(Object.values(global.topPeerCategories).flatMap((category) => category?.peerIds || []));
|
||||
}
|
||||
|
||||
@ -674,6 +674,7 @@ export interface ServiceNotification {
|
||||
|
||||
export interface TopicsInfo {
|
||||
totalCount: number;
|
||||
isCache?: true;
|
||||
topicsById: Record<ThreadId, ApiTopic>;
|
||||
listedTopicIds?: number[];
|
||||
orderedPinnedTopicIds?: number[];
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user