📜 refactor: Optimize Conversation History Nav with Cursor Pagination (#5785)

*  feat: improve Nav/Conversations/Convo/NewChat component performance

*  feat: implement cursor-based pagination for conversations API

* 🔧 refactor: remove createdAt from conversation selection in API and type definitions

* 🔧 refactor: include createdAt in conversation selection and update related types

*  fix: search functionality and bugs with loadMoreConversations

* feat: move ArchivedChats to cursor and DataTable standard

* 🔧 refactor: add InfiniteQueryObserverResult type import in Nav component

* feat: enhance conversation listing with pagination, sorting, and search capabilities

* 🔧 refactor: remove unnecessary comment regarding lodash/debounce in ArchivedChatsTable

* 🔧 refactor: remove unused translation keys for archived chats and search results

* 🔧 fix: Archived Chats, Delete Convo, Duplicate Convo

* 🔧 refactor: improve conversation components with layout adjustments and new translations

* 🔧 refactor: simplify archive conversation mutation and improve unarchive handling; fix: update fork mutation

* 🔧 refactor: decode search query parameter in conversation route; improve error handling in unarchive mutation; clean up DataTable component styles

* 🔧 refactor: remove unused translation key for empty archived chats

* 🚀 fix: `archivedConversation` query key not updated correctly while archiving

* 🧠 feat: Bedrock Anthropic Reasoning & Update Endpoint Handling (#6163)

* feat: Add thinking and thinkingBudget parameters for Bedrock Anthropic models

* chore: Update @librechat/agents to version 2.1.8

* refactor: change region order in params

* refactor: Add maxTokens parameter to conversation preset schema

* refactor: Update agent client to use bedrockInputSchema and improve error handling for model parameters

* refactor: streamline/optimize llmConfig initialization and saving for bedrock

* fix: ensure config titleModel is used for all endpoints

* refactor: enhance OpenAIClient and agent initialization to support endpoint checks for OpenRouter

* chore: bump @google/generative-ai

*  feat: improve Nav/Conversations/Convo/NewChat component performance

* 🔧 refactor: remove unnecessary comment regarding lodash/debounce in ArchivedChatsTable

* 🔧 refactor: update translation keys for clarity; simplify conversation query parameters and improve sorting functionality in SharedLinks component

* 🔧 refactor: optimize conversation loading logic and improve search handling in Nav component

* fix: package-lock

* fix: package-lock 2

* fix: package lock 3

* refactor: remove unused utility files and exports to clean up the codebase

* refactor: remove i18n and useAuthRedirect modules to streamline codebase

* refactor: optimize Conversations component and remove unused ToggleContext

* refactor(Convo): add RenameForm and ConvoLink components; enhance Conversations component with responsive design

* fix: add missing @azure/storage-blob dependency in package.json

* refactor(Search): add error handling with toast notification for search errors

* refactor: make createdAt and updatedAt fields of tConvoUpdateSchema less restrictive if timestamps are missing

* chore: update @azure/storage-blob dependency to version 12.27.0, ensure package-lock is correct

* refactor(Search): improve conversation handling server side

* fix: eslint warning and errors

* refactor(Search): improved search loading state and overall UX

* Refactors conversation cache management

Centralizes conversation mutation logic into dedicated utility functions for adding, updating, and removing conversations from query caches.

Improves reliability and maintainability by:
- Consolidating duplicate cache manipulation code
- Adding type safety for infinite query data structures
- Implementing consistent cache update patterns across all conversation operations
- Removing obsolete conversation helper functions in favor of standardized utilities

* fix: conversation handling and SSE event processing

- Optimizes conversation state management with useMemo and proper hook ordering
- Improves SSE event handler documentation and error handling
- Adds reset guard flag for conversation changes
- Removes redundant navigation call
- Cleans up cursor handling logic and document structure

Improves code maintainability and prevents potential race conditions in conversation state updates

* refactor: add type for SearchBar `onChange`

* fix: type tags

* style: rounded to xl all Header buttons

* fix: activeConvo in Convo not working

* style(Bookmarks): improved UI

* a11y(AccountSettings): fixed hover style not visible when using light theme

* style(SettingsTabs): improved tab switchers and dropdowns

* feat: add translations keys for Speech

* chore: fix package-lock

* fix(mutations): legacy import after rebase

* feat: refactor conversation navigation for accessibility

* fix(search): convo and message create/update date not returned

* fix(search): show correct iconURL and endpoint for searched messages

* fix: small UI improvements

* chore: console.log cleanup

* chore: fix tests

* fix(ChatForm): improve conversation ID handling and clean up useMemo dependencies

* chore: improve typing

* chore: improve typing

* fix(useSSE): clear conversation ID on submission to prevent draft restoration

* refactor(OpenAIClient): clean up abort handler

* refactor(abortMiddleware): change handleAbort to use function expression

* feat: add PENDING_CONVO constant and update conversation ID checks

* fix: final event handling on abort

* fix: improve title sync and query cache sync on final event

* fix: prevent overwriting cached conversation data if it already exists

---------

Co-authored-by: Danny Avila <danny@librechat.ai>
This commit is contained in:
Marco Beretta 2025-04-15 10:04:00 +02:00 committed by GitHub
parent 77a21719fd
commit 650e9b4f6c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
69 changed files with 3434 additions and 2139 deletions

View file

@ -34,6 +34,7 @@ export const useGetToolCalls = <TData = t.ToolCallResults>(
enabled:
conversationId.length > 0 &&
conversationId !== Constants.NEW_CONVO &&
conversationId !== Constants.PENDING_CONVO &&
conversationId !== Constants.SEARCH,
...config,
},

View file

@ -7,19 +7,16 @@ import { useMutation, useQueryClient } from '@tanstack/react-query';
import { dataService, MutationKeys, QueryKeys, defaultOrderQuery } from 'librechat-data-provider';
import type { InfiniteData, UseMutationResult } from '@tanstack/react-query';
import type * as t from 'librechat-data-provider';
import { useConversationTagsQuery, useConversationsInfiniteQuery } from './queries';
import useUpdateTagsInConvo from '~/hooks/Conversations/useUpdateTagsInConvo';
import { updateConversationTag } from '~/utils/conversationTags';
import { normalizeData } from '~/utils/collection';
import {
logger,
/* Conversations */
addConversation,
updateConvoFields,
updateConversation,
deleteConversation,
clearConversationStorage,
addConvoToAllQueries,
updateConvoInAllQueries,
removeConvoFromAllQueries,
} from '~/utils';
import useUpdateTagsInConvo from '~/hooks/Conversations/useUpdateTagsInConvo';
import { updateConversationTag } from '~/utils/conversationTags';
import { useConversationTagsQuery } from './queries';
export type TGenTitleMutation = UseMutationResult<
t.TGenTitleResponse,
@ -28,29 +25,19 @@ export type TGenTitleMutation = UseMutationResult<
unknown
>;
/** Conversations */
export const useGenTitleMutation = (): TGenTitleMutation => {
const queryClient = useQueryClient();
return useMutation((payload: t.TGenTitleRequest) => dataService.genTitle(payload), {
onSuccess: (response, vars) => {
queryClient.setQueryData(
[QueryKeys.conversation, vars.conversationId],
(convo: t.TConversation | undefined) => {
if (!convo) {
return convo;
}
return { ...convo, title: response.title };
},
(convo: t.TConversation | undefined) =>
convo ? { ...convo, title: response.title } : convo,
);
queryClient.setQueryData<t.ConversationData>([QueryKeys.allConversations], (convoData) => {
if (!convoData) {
return convoData;
}
return updateConvoFields(convoData, {
conversationId: vars.conversationId,
title: response.title,
} as t.TConversation);
});
updateConvoInAllQueries(queryClient, vars.conversationId, (c) => ({
...c,
title: response.title,
}));
document.title = response.title;
},
});
@ -70,20 +57,12 @@ export const useUpdateConversationMutation = (
{
onSuccess: (updatedConvo) => {
queryClient.setQueryData([QueryKeys.conversation, id], updatedConvo);
queryClient.setQueryData<t.ConversationData>([QueryKeys.allConversations], (convoData) => {
if (!convoData) {
return convoData;
}
return updateConversation(convoData, updatedConvo);
});
updateConvoInAllQueries(queryClient, id, () => updatedConvo);
},
},
);
};
/**
* Add or remove tags for a conversation
*/
export const useTagConversationMutation = (
conversationId: string,
options?: t.updateTagsInConvoOptions,
@ -95,12 +74,8 @@ export const useTagConversationMutation = (
dataService.addTagToConversation(conversationId, payload),
{
onSuccess: (updatedTags, ...rest) => {
// Because the logic for calculating the bookmark count is complex,
// the client does not perform the calculation,
// but instead refetch the data from the API.
query.refetch();
updateTagsInConversation(conversationId, updatedTags);
options?.onSuccess?.(updatedTags, ...rest);
},
onError: options?.onError,
@ -109,8 +84,8 @@ export const useTagConversationMutation = (
);
};
export const useArchiveConversationMutation = (
id: string,
export const useArchiveConvoMutation = (
options?: t.ArchiveConversationOptions,
): UseMutationResult<
t.TArchiveConversationResponse,
unknown,
@ -118,118 +93,73 @@ export const useArchiveConversationMutation = (
unknown
> => {
const queryClient = useQueryClient();
const { refetch } = useConversationsInfiniteQuery();
const { refetch: archiveRefetch } = useConversationsInfiniteQuery({
pageNumber: '1', // dummy value not used to refetch
isArchived: true,
});
const convoQueryKey = [QueryKeys.allConversations];
const archivedConvoQueryKey = [QueryKeys.archivedConversations];
const { onMutate, onError, onSettled, onSuccess, ..._options } = options || {};
return useMutation(
(payload: t.TArchiveConversationRequest) => dataService.archiveConversation(payload),
{
onSuccess: (_data, vars) => {
onMutate,
onSuccess: (_data, vars, context) => {
const isArchived = vars.isArchived === true;
if (isArchived) {
queryClient.setQueryData([QueryKeys.conversation, id], null);
} else {
queryClient.setQueryData([QueryKeys.conversation, id], _data);
}
queryClient.setQueryData<t.ConversationData>([QueryKeys.allConversations], (convoData) => {
if (!convoData) {
return convoData;
}
const pageSize = convoData.pages[0].pageSize as number;
removeConvoFromAllQueries(queryClient, vars.conversationId);
return normalizeData(
isArchived ? deleteConversation(convoData, id) : addConversation(convoData, _data),
'conversations',
pageSize,
const archivedQueries = queryClient
.getQueryCache()
.findAll([QueryKeys.archivedConversations], { exact: false });
for (const query of archivedQueries) {
queryClient.setQueryData<InfiniteData<ConversationListResponse>>(
query.queryKey,
(oldData) => {
if (!oldData) {
return oldData;
}
if (isArchived) {
return {
...oldData,
pages: [
{
...oldData.pages[0],
conversations: [_data, ...oldData.pages[0].conversations],
},
...oldData.pages.slice(1),
],
};
} else {
return {
...oldData,
pages: oldData.pages.map((page) => ({
...page,
conversations: page.conversations.filter(
(conv) => conv.conversationId !== vars.conversationId,
),
})),
};
}
},
);
});
if (isArchived) {
const current = queryClient.getQueryData<t.ConversationData>([
QueryKeys.allConversations,
]);
refetch({ refetchPage: (page, index) => index === (current?.pages.length ?? 1) - 1 });
}
queryClient.setQueryData<t.ConversationData>(
[QueryKeys.archivedConversations],
(convoData) => {
if (!convoData) {
return convoData;
}
const pageSize = convoData.pages[0].pageSize as number;
return normalizeData(
isArchived ? addConversation(convoData, _data) : deleteConversation(convoData, id),
'conversations',
pageSize,
);
},
queryClient.setQueryData(
[QueryKeys.conversation, vars.conversationId],
isArchived ? null : _data,
);
if (!isArchived) {
const currentArchive = queryClient.getQueryData<t.ConversationData>([
QueryKeys.archivedConversations,
]);
archiveRefetch({
refetchPage: (page, index) => index === (currentArchive?.pages.length ?? 1) - 1,
});
}
onSuccess?.(_data, vars, context);
},
},
);
};
export const useArchiveConvoMutation = (options?: t.ArchiveConvoOptions) => {
const queryClient = useQueryClient();
const { onSuccess, ..._options } = options ?? {};
return useMutation<t.TArchiveConversationResponse, unknown, t.TArchiveConversationRequest>(
(payload: t.TArchiveConversationRequest) => dataService.archiveConversation(payload),
{
onSuccess: (_data, vars) => {
const { conversationId } = vars;
const isArchived = vars.isArchived === true;
if (isArchived) {
queryClient.setQueryData([QueryKeys.conversation, conversationId], null);
} else {
queryClient.setQueryData([QueryKeys.conversation, conversationId], _data);
}
queryClient.setQueryData<t.ConversationData>([QueryKeys.allConversations], (convoData) => {
if (!convoData) {
return convoData;
}
const pageSize = convoData.pages[0].pageSize as number;
return normalizeData(
isArchived
? deleteConversation(convoData, conversationId)
: addConversation(convoData, _data),
'conversations',
pageSize,
);
onError,
onSettled: () => {
queryClient.invalidateQueries({
queryKey: convoQueryKey,
refetchPage: (_, index) => index === 0,
});
queryClient.invalidateQueries({
queryKey: archivedConvoQueryKey,
refetchPage: (_, index) => index === 0,
});
queryClient.setQueryData<t.ConversationData>(
[QueryKeys.archivedConversations],
(convoData) => {
if (!convoData) {
return convoData;
}
const pageSize = convoData.pages[0].pageSize as number;
return normalizeData(
isArchived
? addConversation(convoData, _data)
: deleteConversation(convoData, conversationId),
'conversations',
pageSize,
);
},
);
onSuccess?.(_data, vars);
},
..._options,
},
@ -457,20 +387,21 @@ export const useDeleteTagInConversations = () => {
QueryKeys.allConversations,
]);
const conversationIdsWithTag = [] as string[];
const conversationIdsWithTag: string[] = [];
// remove deleted tag from conversations
// Remove deleted tag from conversations
const newData = JSON.parse(JSON.stringify(data)) as InfiniteData<ConversationListResponse>;
for (let pageIndex = 0; pageIndex < newData.pages.length; pageIndex++) {
const page = newData.pages[pageIndex];
page.conversations = page.conversations.map((conversation) => {
if (
conversation.conversationId != null &&
conversation.conversationId &&
conversation.tags?.includes(deletedTag) === true
'tags' in conversation &&
Array.isArray(conversation.tags) &&
conversation.tags.includes(deletedTag)
) {
conversationIdsWithTag.push(conversation.conversationId);
conversation.tags = conversation.tags.filter((t) => t !== deletedTag);
conversation.tags = conversation.tags.filter((tag: string) => tag !== deletedTag);
}
return conversation;
});
@ -487,8 +418,8 @@ export const useDeleteTagInConversations = () => {
QueryKeys.conversation,
conversationId,
]);
if (conversationData && conversationData.tags) {
conversationData.tags = conversationData.tags.filter((t) => t !== deletedTag);
if (conversationData && 'tags' in conversationData && Array.isArray(conversationData.tags)) {
conversationData.tags = conversationData.tags.filter((tag: string) => tag !== deletedTag);
queryClient.setQueryData<t.TConversation>(
[QueryKeys.conversation, conversationId],
conversationData,
@ -498,7 +429,7 @@ export const useDeleteTagInConversations = () => {
};
return deleteTagInAllConversation;
};
// Delete a tag
export const useDeleteConversationTagMutation = (
options?: t.DeleteConversationTagOptions,
): UseMutationResult<t.TConversationTagResponse, unknown, string, void> => {
@ -532,40 +463,67 @@ export const useDeleteConversationMutation = (
unknown
> => {
const queryClient = useQueryClient();
const { refetch } = useConversationsInfiniteQuery();
const { onSuccess, ..._options } = options || {};
return useMutation(
(payload: t.TDeleteConversationRequest) => dataService.deleteConversation(payload),
(payload: t.TDeleteConversationRequest) =>
dataService.deleteConversation(payload) as Promise<t.TDeleteConversationResponse>,
{
onSuccess: (_data, vars, context) => {
const conversationId = vars.conversationId ?? '';
if (!conversationId) {
return;
onMutate: async () => {
await queryClient.cancelQueries([QueryKeys.allConversations]);
await queryClient.cancelQueries([QueryKeys.archivedConversations]);
// could store old state if needed for rollback
},
onError: () => {
// TODO: CHECK THIS, no-op; restore if needed
},
onSuccess: (data, vars, context) => {
if (vars.conversationId) {
removeConvoFromAllQueries(queryClient, vars.conversationId);
}
const handleDelete = (convoData: t.ConversationData | undefined) => {
if (!convoData) {
return convoData;
}
return normalizeData(
deleteConversation(convoData, conversationId),
'conversations',
Number(convoData.pages[0].pageSize),
);
};
// Also remove from all archivedConversations caches
const archivedQueries = queryClient
.getQueryCache()
.findAll([QueryKeys.archivedConversations], { exact: false });
queryClient.setQueryData([QueryKeys.conversation, conversationId], null);
queryClient.setQueryData<t.ConversationData>([QueryKeys.allConversations], handleDelete);
queryClient.setQueryData<t.ConversationData>(
[QueryKeys.archivedConversations],
handleDelete,
);
const current = queryClient.getQueryData<t.ConversationData>([QueryKeys.allConversations]);
refetch({ refetchPage: (page, index) => index === (current?.pages.length ?? 1) - 1 });
onSuccess?.(_data, vars, context);
clearConversationStorage(conversationId);
for (const query of archivedQueries) {
queryClient.setQueryData<InfiniteData<ConversationListResponse>>(
query.queryKey,
(oldData) => {
if (!oldData) {
return oldData;
}
return {
...oldData,
pages: oldData.pages
.map((page) => ({
...page,
conversations: page.conversations.filter(
(conv) => conv.conversationId !== vars.conversationId,
),
}))
.filter((page) => page.conversations.length > 0),
};
},
);
}
queryClient.removeQueries({
queryKey: [QueryKeys.conversation, vars.conversationId],
exact: true,
});
queryClient.invalidateQueries({
queryKey: [QueryKeys.allConversations],
refetchPage: (_, index) => index === 0,
});
queryClient.invalidateQueries({
queryKey: [QueryKeys.archivedConversations],
refetchPage: (_, index) => index === 0,
});
options?.onSuccess?.(data, vars, context);
},
..._options,
},
);
};
@ -577,24 +535,23 @@ export const useDuplicateConversationMutation = (
const { onSuccess, ..._options } = options ?? {};
return useMutation((payload) => dataService.duplicateConversation(payload), {
onSuccess: (data, vars, context) => {
const originalId = vars.conversationId ?? '';
if (originalId.length === 0) {
const duplicatedConversation = data.conversation;
if (!duplicatedConversation?.conversationId) {
return;
}
queryClient.setQueryData(
[QueryKeys.conversation, data.conversation.conversationId],
data.conversation,
[QueryKeys.conversation, duplicatedConversation.conversationId],
duplicatedConversation,
);
queryClient.setQueryData<t.ConversationData>([QueryKeys.allConversations], (convoData) => {
if (!convoData) {
return convoData;
}
return addConversation(convoData, data.conversation);
});
queryClient.setQueryData<t.TMessage[]>(
[QueryKeys.messages, data.conversation.conversationId],
addConvoToAllQueries(queryClient, duplicatedConversation);
queryClient.setQueryData(
[QueryKeys.messages, duplicatedConversation.conversationId],
data.messages,
);
queryClient.invalidateQueries({
queryKey: [QueryKeys.allConversations],
refetchPage: (_, index) => index === 0,
});
onSuccess?.(data, vars, context);
},
..._options,
@ -606,25 +563,25 @@ export const useForkConvoMutation = (
): UseMutationResult<t.TForkConvoResponse, unknown, t.TForkConvoRequest, unknown> => {
const queryClient = useQueryClient();
const { onSuccess, ..._options } = options || {};
return useMutation((payload: t.TForkConvoRequest) => dataService.forkConversation(payload), {
onSuccess: (data, vars, context) => {
if (!vars.conversationId) {
return;
}
queryClient.setQueryData(
[QueryKeys.conversation, data.conversation.conversationId],
data.conversation,
);
queryClient.setQueryData<t.ConversationData>([QueryKeys.allConversations], (convoData) => {
if (!convoData) {
return convoData;
}
return addConversation(convoData, data.conversation);
const forkedConversation = data.conversation;
const forkedConversationId = forkedConversation.conversationId;
if (!forkedConversationId) {
return;
}
queryClient.setQueryData([QueryKeys.conversation, forkedConversationId], forkedConversation);
addConvoToAllQueries(queryClient, forkedConversation);
queryClient.setQueryData([QueryKeys.messages, forkedConversationId], data.messages);
queryClient.invalidateQueries({
queryKey: [QueryKeys.allConversations],
refetchPage: (_, index) => index === 0,
});
queryClient.setQueryData<t.TMessage[]>(
[QueryKeys.messages, data.conversation.conversationId],
data.messages,
);
onSuccess?.(data, vars, context);
},
..._options,
@ -899,7 +856,6 @@ export const useUploadAssistantAvatarMutation = (
unknown // context
> => {
return useMutation([MutationKeys.assistantAvatarUpload], {
mutationFn: ({ postCreation, ...variables }: t.AssistantAvatarVariables) =>
dataService.uploadAssistantAvatar(variables),
...(options || {}),

View file

@ -5,9 +5,9 @@ import {
defaultOrderQuery,
defaultAssistantsVersion,
} from 'librechat-data-provider';
import { useRecoilValue } from 'recoil';
import { useQuery, useInfiniteQuery, useQueryClient } from '@tanstack/react-query';
import type {
InfiniteData,
UseInfiniteQueryOptions,
QueryObserverResult,
UseQueryOptions,
@ -19,6 +19,8 @@ import type {
TPlugin,
ConversationListResponse,
ConversationListParams,
SearchConversationListResponse,
SearchConversationListParams,
Assistant,
AssistantListParams,
AssistantListResponse,
@ -28,8 +30,6 @@ import type {
SharedLinksListParams,
SharedLinksResponse,
} from 'librechat-data-provider';
import { findPageForConversation } from '~/utils';
import store from '~/store';
export const useGetPresetsQuery = (
config?: UseQueryOptions<TPreset[]>,
@ -63,25 +63,23 @@ export const useGetConvoIdQuery = (
config?: UseQueryOptions<t.TConversation>,
): QueryObserverResult<t.TConversation> => {
const queryClient = useQueryClient();
return useQuery<t.TConversation>(
[QueryKeys.conversation, id],
() => {
const defaultQuery = () => dataService.getConversationById(id);
const convosQuery = queryClient.getQueryData<t.ConversationData>([
QueryKeys.allConversations,
]);
// Try to find in all fetched infinite pages
const convosQuery = queryClient.getQueryData<
InfiniteData<import('~/utils').ConversationCursorData>
>([QueryKeys.allConversations]);
const found = convosQuery?.pages
.flatMap((page) => page.conversations)
.find((c) => c.conversationId === id);
if (!convosQuery) {
return defaultQuery();
if (found) {
return found;
}
const { pageIndex, index } = findPageForConversation(convosQuery, { conversationId: id });
if (pageIndex > -1 && index > -1) {
return convosQuery.pages[pageIndex].conversations[index];
}
return defaultQuery();
// Otherwise, fetch from API
return dataService.getConversationById(id);
},
{
refetchOnWindowFocus: false,
@ -93,19 +91,21 @@ export const useGetConvoIdQuery = (
};
export const useSearchInfiniteQuery = (
params?: ConversationListParams & { searchQuery?: string },
config?: UseInfiniteQueryOptions<ConversationListResponse, unknown>,
params?: SearchConversationListParams,
config?: UseInfiniteQueryOptions<SearchConversationListResponse, unknown>,
) => {
return useInfiniteQuery<ConversationListResponse, unknown>(
[QueryKeys.searchConversations, params], // Include the searchQuery in the query key
({ pageParam = '1' }) =>
dataService.listConversationsByQuery({ ...params, pageNumber: pageParam }),
return useInfiniteQuery<SearchConversationListResponse, unknown>(
[QueryKeys.searchConversations, params],
({ pageParam = null }) =>
dataService
.listConversations({
...params,
search: params?.search ?? '',
cursor: pageParam?.toString(),
})
.then((res) => ({ ...res })) as Promise<SearchConversationListResponse>,
{
getNextPageParam: (lastPage) => {
const currentPageNumber = Number(lastPage.pageNumber);
const totalPages = Number(lastPage.pages);
return currentPageNumber < totalPages ? currentPageNumber + 1 : undefined;
},
getNextPageParam: (lastPage) => lastPage.nextCursor ?? undefined,
refetchOnWindowFocus: false,
refetchOnReconnect: false,
refetchOnMount: false,
@ -115,33 +115,31 @@ export const useSearchInfiniteQuery = (
};
export const useConversationsInfiniteQuery = (
params?: ConversationListParams,
params: ConversationListParams,
config?: UseInfiniteQueryOptions<ConversationListResponse, unknown>,
) => {
const queriesEnabled = useRecoilValue<boolean>(store.queriesEnabled);
return useInfiniteQuery<ConversationListResponse, unknown>(
params?.isArchived === true ? [QueryKeys.archivedConversations] : [QueryKeys.allConversations],
({ pageParam = '' }) =>
const { isArchived, sortBy, sortDirection, tags, search } = params;
return useInfiniteQuery<ConversationListResponse>({
queryKey: [
isArchived ? QueryKeys.archivedConversations : QueryKeys.allConversations,
{ isArchived, sortBy, sortDirection, tags, search },
],
queryFn: ({ pageParam }) =>
dataService.listConversations({
...params,
pageNumber: pageParam?.toString(),
isArchived: params?.isArchived ?? false,
tags: params?.tags || [],
isArchived,
sortBy,
sortDirection,
tags,
search,
cursor: pageParam?.toString(),
}),
{
getNextPageParam: (lastPage) => {
const currentPageNumber = Number(lastPage.pageNumber);
const totalPages = Number(lastPage.pages); // Convert totalPages to a number
// If the current page number is less than total pages, return the next page number
return currentPageNumber < totalPages ? currentPageNumber + 1 : undefined;
},
refetchOnWindowFocus: false,
refetchOnReconnect: false,
refetchOnMount: false,
...config,
enabled: (config?.enabled ?? true) === true && queriesEnabled,
},
);
getNextPageParam: (lastPage) => lastPage.nextCursor ?? undefined,
keepPreviousData: true,
staleTime: 5 * 60 * 1000, // 5 minutes
cacheTime: 30 * 60 * 1000, // 30 minutes
...config,
});
};
export const useSharedLinksQuery = (