import { Constants, defaultAssistantsVersion, ConversationListResponse, } from 'librechat-data-provider'; 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, } from '~/utils'; export type TGenTitleMutation = UseMutationResult< t.TGenTitleResponse, unknown, t.TGenTitleRequest, 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 }; }, ); queryClient.setQueryData([QueryKeys.allConversations], (convoData) => { if (!convoData) { return convoData; } return updateConvoFields(convoData, { conversationId: vars.conversationId, title: response.title, } as t.TConversation); }); document.title = response.title; }, }); }; export const useUpdateConversationMutation = ( id: string, ): UseMutationResult< t.TUpdateConversationResponse, unknown, t.TUpdateConversationRequest, unknown > => { const queryClient = useQueryClient(); return useMutation( (payload: t.TUpdateConversationRequest) => dataService.updateConversation(payload), { onSuccess: (updatedConvo) => { queryClient.setQueryData([QueryKeys.conversation, id], updatedConvo); queryClient.setQueryData([QueryKeys.allConversations], (convoData) => { if (!convoData) { return convoData; } return updateConversation(convoData, updatedConvo); }); }, }, ); }; /** * Add or remove tags for a conversation */ export const useTagConversationMutation = ( conversationId: string, options?: t.updateTagsInConvoOptions, ): UseMutationResult => { const query = useConversationTagsQuery(); const { updateTagsInConversation } = useUpdateTagsInConvo(); return useMutation( (payload: t.TTagConversationRequest) => 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, onMutate: options?.onMutate, }, ); }; export const useArchiveConversationMutation = ( id: string, ): UseMutationResult< t.TArchiveConversationResponse, unknown, t.TArchiveConversationRequest, unknown > => { const queryClient = useQueryClient(); const { refetch } = useConversationsInfiniteQuery(); const { refetch: archiveRefetch } = useConversationsInfiniteQuery({ pageNumber: '1', // dummy value not used to refetch isArchived: true, }); return useMutation( (payload: t.TArchiveConversationRequest) => dataService.archiveConversation(payload), { onSuccess: (_data, vars) => { const isArchived = vars.isArchived === true; if (isArchived) { queryClient.setQueryData([QueryKeys.conversation, id], null); } else { queryClient.setQueryData([QueryKeys.conversation, id], _data); } queryClient.setQueryData([QueryKeys.allConversations], (convoData) => { if (!convoData) { return convoData; } const pageSize = convoData.pages[0].pageSize as number; return normalizeData( isArchived ? deleteConversation(convoData, id) : addConversation(convoData, _data), 'conversations', pageSize, ); }); if (isArchived) { const current = queryClient.getQueryData([ QueryKeys.allConversations, ]); refetch({ refetchPage: (page, index) => index === (current?.pages.length ?? 1) - 1 }); } queryClient.setQueryData( [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, ); }, ); if (!isArchived) { const currentArchive = queryClient.getQueryData([ QueryKeys.archivedConversations, ]); archiveRefetch({ refetchPage: (page, index) => index === (currentArchive?.pages.length ?? 1) - 1, }); } }, }, ); }; export const useArchiveConvoMutation = (options?: t.ArchiveConvoOptions) => { const queryClient = useQueryClient(); const { onSuccess, ..._options } = options ?? {}; return useMutation( (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([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, ); }); queryClient.setQueryData( [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, }, ); }; export const useCreateSharedLinkMutation = ( options?: t.MutationOptions, ): UseMutationResult => { const queryClient = useQueryClient(); const { onSuccess, ..._options } = options || {}; return useMutation( ({ conversationId }: { conversationId: string }) => { if (!conversationId) { throw new Error('Conversation ID is required'); } return dataService.createSharedLink(conversationId); }, { onSuccess: (_data: t.TSharedLinkResponse, vars, context) => { queryClient.setQueryData([QueryKeys.sharedLinks, _data.conversationId], _data); onSuccess?.(_data, vars, context); }, ..._options, }, ); }; export const useUpdateSharedLinkMutation = ( options?: t.MutationOptions, ): UseMutationResult => { const queryClient = useQueryClient(); const { onSuccess, ..._options } = options || {}; return useMutation( ({ shareId }) => { if (!shareId) { throw new Error('Share ID is required'); } return dataService.updateSharedLink(shareId); }, { onSuccess: (_data: t.TSharedLinkResponse, vars, context) => { queryClient.setQueryData([QueryKeys.sharedLinks, _data.conversationId], _data); onSuccess?.(_data, vars, context); }, ..._options, }, ); }; export const useDeleteSharedLinkMutation = ( options?: t.DeleteSharedLinkOptions, ): UseMutationResult< t.TDeleteSharedLinkResponse, unknown, { shareId: string }, t.DeleteSharedLinkContext > => { const queryClient = useQueryClient(); const { onSuccess } = options || {}; return useMutation((vars) => dataService.deleteSharedLink(vars.shareId), { onMutate: async (vars) => { await queryClient.cancelQueries({ queryKey: [QueryKeys.sharedLinks], exact: false, }); const previousQueries = new Map(); const queryKeys = queryClient.getQueryCache().findAll([QueryKeys.sharedLinks]); queryKeys.forEach((query) => { const previousData = queryClient.getQueryData(query.queryKey); previousQueries.set(query.queryKey, previousData); queryClient.setQueryData(query.queryKey, (old) => { if (!old?.pages) { return old; } const updatedPages = old.pages.map((page) => ({ ...page, links: page.links.filter((link) => link.shareId !== vars.shareId), })); const nonEmptyPages = updatedPages.filter((page) => page.links.length > 0); return { ...old, pages: nonEmptyPages, }; }); }); return { previousQueries }; }, onError: (_err, _vars, context) => { if (context?.previousQueries) { context.previousQueries.forEach((prevData: unknown, prevQueryKey: unknown) => { queryClient.setQueryData(prevQueryKey as string[], prevData); }); } }, onSettled: () => { queryClient.invalidateQueries({ queryKey: [QueryKeys.sharedLinks], exact: false, }); }, onSuccess: (data, variables) => { if (onSuccess) { onSuccess(data, variables); } queryClient.refetchQueries({ queryKey: [QueryKeys.sharedLinks], exact: true, }); }, }); }; // Add a tag or update tag information (tag, description, position, etc.) export const useConversationTagMutation = ({ context, tag, options, }: { context: string; tag?: string; options?: t.UpdateConversationTagOptions; }): UseMutationResult => { const queryClient = useQueryClient(); const { onSuccess, ..._options } = options || {}; const onMutationSuccess: typeof onSuccess = (_data, vars) => { queryClient.setQueryData([QueryKeys.conversationTags], (queryData) => { if (!queryData) { return [ { count: 1, position: 0, tag: Constants.SAVED_TAG, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), }, ] as t.TConversationTag[]; } if (tag === undefined || !tag.length) { // Check if the tag already exists const existingTagIndex = queryData.findIndex((item) => item.tag === _data.tag); if (existingTagIndex !== -1) { logger.log( 'tag_mutation', `"Created" tag exists, updating from ${context}`, queryData, _data, ); // If the tag exists, update it const updatedData = [...queryData]; updatedData[existingTagIndex] = { ...updatedData[existingTagIndex], ..._data }; return updatedData.sort((a, b) => a.position - b.position); } else { // If the tag doesn't exist, add it logger.log( 'tag_mutation', `"Created" tag is new, adding from ${context}`, queryData, _data, ); return [...queryData, _data].sort((a, b) => a.position - b.position); } } logger.log('tag_mutation', `Updating tag from ${context}`, queryData, _data); return updateConversationTag(queryData, vars, _data, tag); }); if (vars.addToConversation === true && vars.conversationId != null && _data.tag) { const currentConvo = queryClient.getQueryData([ QueryKeys.conversation, vars.conversationId, ]); if (!currentConvo) { return; } logger.log( 'tag_mutation', `\`updateTagsInConversation\` Update from ${context}`, currentConvo, ); updateTagsInConversation(vars.conversationId, [...(currentConvo.tags || []), _data.tag]); } // Change the tag title to the new title if (tag != null) { replaceTagsInAllConversations(tag, _data.tag); } }; const { updateTagsInConversation, replaceTagsInAllConversations } = useUpdateTagsInConvo(); return useMutation( (payload: t.TConversationTagRequest) => tag != null ? dataService.updateConversationTag(tag, payload) : dataService.createConversationTag(payload), { onSuccess: (...args) => { onMutationSuccess(...args); onSuccess?.(...args); }, ..._options, }, ); }; // When a bookmark is deleted, remove that bookmark(tag) from all conversations associated with it export const useDeleteTagInConversations = () => { const queryClient = useQueryClient(); const deleteTagInAllConversation = (deletedTag: string) => { const data = queryClient.getQueryData>([ QueryKeys.allConversations, ]); const conversationIdsWithTag = [] as string[]; // remove deleted tag from conversations const newData = JSON.parse(JSON.stringify(data)) as InfiniteData; 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 ) { conversationIdsWithTag.push(conversation.conversationId); conversation.tags = conversation.tags.filter((t) => t !== deletedTag); } return conversation; }); } queryClient.setQueryData>( [QueryKeys.allConversations], newData, ); // Remove the deleted tag from the cache of each conversation for (let i = 0; i < conversationIdsWithTag.length; i++) { const conversationId = conversationIdsWithTag[i]; const conversationData = queryClient.getQueryData([ QueryKeys.conversation, conversationId, ]); if (conversationData && conversationData.tags) { conversationData.tags = conversationData.tags.filter((t) => t !== deletedTag); queryClient.setQueryData( [QueryKeys.conversation, conversationId], conversationData, ); } } }; return deleteTagInAllConversation; }; // Delete a tag export const useDeleteConversationTagMutation = ( options?: t.DeleteConversationTagOptions, ): UseMutationResult => { const queryClient = useQueryClient(); const deleteTagInAllConversations = useDeleteTagInConversations(); const { onSuccess, ..._options } = options || {}; return useMutation((tag: string) => dataService.deleteConversationTag(tag), { onSuccess: (_data, tagToDelete, context) => { queryClient.setQueryData([QueryKeys.conversationTags], (data) => { if (!data) { return data; } return data.filter((t) => t.tag !== tagToDelete); }); deleteTagInAllConversations(tagToDelete); onSuccess?.(_data, tagToDelete, context); }, ..._options, }); }; export const useDeleteConversationMutation = ( options?: t.DeleteConversationOptions, ): UseMutationResult< t.TDeleteConversationResponse, unknown, t.TDeleteConversationRequest, unknown > => { const queryClient = useQueryClient(); const { refetch } = useConversationsInfiniteQuery(); const { onSuccess, ..._options } = options || {}; return useMutation( (payload: t.TDeleteConversationRequest) => dataService.deleteConversation(payload), { onSuccess: (_data, vars, context) => { const conversationId = vars.conversationId ?? ''; if (!conversationId) { return; } const handleDelete = (convoData: t.ConversationData | undefined) => { if (!convoData) { return convoData; } return normalizeData( deleteConversation(convoData, conversationId), 'conversations', Number(convoData.pages[0].pageSize), ); }; queryClient.setQueryData([QueryKeys.conversation, conversationId], null); queryClient.setQueryData([QueryKeys.allConversations], handleDelete); queryClient.setQueryData( [QueryKeys.archivedConversations], handleDelete, ); const current = queryClient.getQueryData([QueryKeys.allConversations]); refetch({ refetchPage: (page, index) => index === (current?.pages.length ?? 1) - 1 }); onSuccess?.(_data, vars, context); }, ..._options, }, ); }; export const useDuplicateConversationMutation = ( options?: t.DuplicateConvoOptions, ): UseMutationResult => { const queryClient = useQueryClient(); const { onSuccess, ..._options } = options ?? {}; return useMutation((payload) => dataService.duplicateConversation(payload), { onSuccess: (data, vars, context) => { const originalId = vars.conversationId ?? ''; if (originalId.length === 0) { return; } queryClient.setQueryData( [QueryKeys.conversation, data.conversation.conversationId], data.conversation, ); queryClient.setQueryData([QueryKeys.allConversations], (convoData) => { if (!convoData) { return convoData; } return addConversation(convoData, data.conversation); }); queryClient.setQueryData( [QueryKeys.messages, data.conversation.conversationId], data.messages, ); onSuccess?.(data, vars, context); }, ..._options, }); }; export const useForkConvoMutation = ( options?: t.ForkConvoOptions, ): UseMutationResult => { 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([QueryKeys.allConversations], (convoData) => { if (!convoData) { return convoData; } return addConversation(convoData, data.conversation); }); queryClient.setQueryData( [QueryKeys.messages, data.conversation.conversationId], data.messages, ); onSuccess?.(data, vars, context); }, ..._options, }); }; export const useUploadConversationsMutation = ( _options?: t.MutationOptions, ) => { const queryClient = useQueryClient(); const { onSuccess, onError, onMutate } = _options || {}; return useMutation({ mutationFn: (formData: FormData) => dataService.importConversationsFile(formData), onSuccess: (data, variables, context) => { /* TODO: optimize to return imported conversations and add manually */ queryClient.invalidateQueries([QueryKeys.allConversations]); if (onSuccess) { onSuccess(data, variables, context); } }, onError: (err, variables, context) => { if (onError) { onError(err, variables, context); } }, onMutate, }); }; export const useUpdatePresetMutation = ( options?: t.UpdatePresetOptions, ): UseMutationResult< t.TPreset, // response data unknown, t.TPreset, unknown > => { return useMutation([MutationKeys.updatePreset], { mutationFn: (preset: t.TPreset) => dataService.updatePreset(preset), ...(options || {}), }); }; export const useDeletePresetMutation = ( options?: t.DeletePresetOptions, ): UseMutationResult< t.PresetDeleteResponse, // response data unknown, t.TPreset | undefined, unknown > => { return useMutation([MutationKeys.deletePreset], { mutationFn: (preset: t.TPreset | undefined) => dataService.deletePreset(preset), ...(options || {}), }); }; /* Avatar upload */ export const useUploadAvatarMutation = ( options?: t.UploadAvatarOptions, ): UseMutationResult< t.AvatarUploadResponse, // response data unknown, // error FormData, // request unknown // context > => { return useMutation([MutationKeys.avatarUpload], { mutationFn: (variables: FormData) => dataService.uploadAvatar(variables), ...(options || {}), }); }; /* Speech to text */ export const useSpeechToTextMutation = ( options?: t.SpeechToTextOptions, ): UseMutationResult< t.SpeechToTextResponse, // response data unknown, // error FormData, // request unknown // context > => { return useMutation([MutationKeys.speechToText], { mutationFn: (variables: FormData) => dataService.speechToText(variables), ...(options || {}), }); }; /* Text to speech */ export const useTextToSpeechMutation = ( options?: t.TextToSpeechOptions, ): UseMutationResult< ArrayBuffer, // response data unknown, // error FormData, // request unknown // context > => { return useMutation([MutationKeys.textToSpeech], { mutationFn: (variables: FormData) => dataService.textToSpeech(variables), ...(options || {}), }); }; /** * ASSISTANTS */ /** * Create a new assistant */ export const useCreateAssistantMutation = ( options?: t.CreateAssistantMutationOptions, ): UseMutationResult => { const queryClient = useQueryClient(); return useMutation( (newAssistantData: t.AssistantCreateParams) => dataService.createAssistant(newAssistantData), { onMutate: (variables) => options?.onMutate?.(variables), onError: (error, variables, context) => options?.onError?.(error, variables, context), onSuccess: (newAssistant, variables, context) => { const listRes = queryClient.getQueryData([ QueryKeys.assistants, variables.endpoint, defaultOrderQuery, ]); if (!listRes) { return options?.onSuccess?.(newAssistant, variables, context); } const currentAssistants = [newAssistant, ...JSON.parse(JSON.stringify(listRes.data))]; queryClient.setQueryData( [QueryKeys.assistants, variables.endpoint, defaultOrderQuery], { ...listRes, data: currentAssistants, }, ); return options?.onSuccess?.(newAssistant, variables, context); }, }, ); }; /** * Hook for updating an assistant */ export const useUpdateAssistantMutation = ( options?: t.UpdateAssistantMutationOptions, ): UseMutationResult< t.Assistant, Error, { assistant_id: string; data: t.AssistantUpdateParams } > => { const queryClient = useQueryClient(); return useMutation( ({ assistant_id, data }: { assistant_id: string; data: t.AssistantUpdateParams }) => { const { endpoint } = data; const endpointsConfig = queryClient.getQueryData([QueryKeys.endpoints]); const endpointConfig = endpointsConfig?.[endpoint]; const version = endpointConfig?.version ?? defaultAssistantsVersion[endpoint]; return dataService.updateAssistant({ data, version, assistant_id, }); }, { onMutate: (variables) => options?.onMutate?.(variables), onError: (error, variables, context) => options?.onError?.(error, variables, context), onSuccess: (updatedAssistant, variables, context) => { const listRes = queryClient.getQueryData([ QueryKeys.assistants, variables.data.endpoint, defaultOrderQuery, ]); if (!listRes) { return options?.onSuccess?.(updatedAssistant, variables, context); } queryClient.setQueryData( [QueryKeys.assistantDocs, variables.data.endpoint], (prev) => { if (!prev) { return prev; } return prev.map((doc) => { if (doc.assistant_id === variables.assistant_id) { return { ...doc, conversation_starters: updatedAssistant.conversation_starters, append_current_datetime: variables.data.append_current_datetime, }; } return doc; }); }, ); queryClient.setQueryData( [QueryKeys.assistants, variables.data.endpoint, defaultOrderQuery], { ...listRes, data: listRes.data.map((assistant) => { if (assistant.id === variables.assistant_id) { return updatedAssistant; } return assistant; }), }, ); return options?.onSuccess?.(updatedAssistant, variables, context); }, }, ); }; /** * Hook for deleting an assistant */ export const useDeleteAssistantMutation = ( options?: t.DeleteAssistantMutationOptions, ): UseMutationResult => { const queryClient = useQueryClient(); return useMutation( ({ assistant_id, model, endpoint }: t.DeleteAssistantBody) => { const endpointsConfig = queryClient.getQueryData([QueryKeys.endpoints]); const version = endpointsConfig?.[endpoint]?.version ?? defaultAssistantsVersion[endpoint]; return dataService.deleteAssistant({ assistant_id, model, version, endpoint }); }, { onMutate: (variables) => options?.onMutate?.(variables), onError: (error, variables, context) => options?.onError?.(error, variables, context), onSuccess: (_data, variables, context) => { const listRes = queryClient.getQueryData([ QueryKeys.assistants, variables.endpoint, defaultOrderQuery, ]); if (!listRes) { return options?.onSuccess?.(_data, variables, context); } const data = listRes.data.filter((assistant) => assistant.id !== variables.assistant_id); queryClient.setQueryData( [QueryKeys.assistants, variables.endpoint, defaultOrderQuery], { ...listRes, data, }, ); return options?.onSuccess?.(_data, variables, data); }, }, ); }; /** * Hook for uploading an assistant avatar */ export const useUploadAssistantAvatarMutation = ( options?: t.UploadAssistantAvatarOptions, ): UseMutationResult< t.Assistant, // response data unknown, // error t.AssistantAvatarVariables, // request unknown // context > => { return useMutation([MutationKeys.assistantAvatarUpload], { // eslint-disable-next-line @typescript-eslint/no-unused-vars mutationFn: ({ postCreation, ...variables }: t.AssistantAvatarVariables) => dataService.uploadAssistantAvatar(variables), ...(options || {}), }); }; /** * Hook for updating Assistant Actions */ export const useUpdateAction = ( options?: t.UpdateActionOptions, ): UseMutationResult< t.UpdateActionResponse, // response data unknown, // error t.UpdateActionVariables, // request unknown // context > => { const queryClient = useQueryClient(); return useMutation([MutationKeys.updateAction], { mutationFn: (variables: t.UpdateActionVariables) => dataService.updateAction(variables), onMutate: (variables) => options?.onMutate?.(variables), onError: (error, variables, context) => options?.onError?.(error, variables, context), onSuccess: (updateActionResponse, variables, context) => { const listRes = queryClient.getQueryData([ QueryKeys.assistants, variables.endpoint, defaultOrderQuery, ]); if (!listRes) { return options?.onSuccess?.(updateActionResponse, variables, context); } const updatedAssistant = updateActionResponse[1]; queryClient.setQueryData( [QueryKeys.assistants, variables.endpoint, defaultOrderQuery], { ...listRes, data: listRes.data.map((assistant) => { if (assistant.id === variables.assistant_id) { return updatedAssistant; } return assistant; }), }, ); queryClient.setQueryData([QueryKeys.actions], (prev) => { return prev ?.map((action) => { if (action.action_id === variables.action_id) { return updateActionResponse[2]; } return action; }) .concat( variables.action_id != null && variables.action_id ? [] : [updateActionResponse[2]], ); }); return options?.onSuccess?.(updateActionResponse, variables, context); }, }); }; /** * Hook for deleting an Assistant Action */ export const useDeleteAction = ( options?: t.DeleteActionOptions, ): UseMutationResult< void, // response data for a delete operation is typically void Error, // error type t.DeleteActionVariables, // request variables unknown // context > => { const queryClient = useQueryClient(); return useMutation([MutationKeys.deleteAction], { mutationFn: (variables: t.DeleteActionVariables) => { const { endpoint } = variables; const endpointsConfig = queryClient.getQueryData([QueryKeys.endpoints]); const version = endpointsConfig?.[endpoint]?.version ?? defaultAssistantsVersion[endpoint]; return dataService.deleteAction({ ...variables, version, }); }, onMutate: (variables) => options?.onMutate?.(variables), onError: (error, variables, context) => options?.onError?.(error, variables, context), onSuccess: (_data, variables, context) => { let domain: string | undefined = ''; queryClient.setQueryData([QueryKeys.actions], (prev) => { return prev?.filter((action) => { domain = action.metadata.domain; return action.action_id !== variables.action_id; }); }); queryClient.setQueryData( [QueryKeys.assistants, variables.endpoint, defaultOrderQuery], (prev) => { if (!prev) { return prev; } return { ...prev, data: prev.data.map((assistant) => { if (assistant.id === variables.assistant_id) { return { ...assistant, tools: (assistant.tools ?? []).filter( (tool) => !(tool.function?.name.includes(domain ?? '') ?? false), ), }; } return assistant; }), }; }, ); return options?.onSuccess?.(_data, variables, context); }, }); }; /** * Hook for verifying email address */ export const useVerifyEmailMutation = ( options?: t.VerifyEmailOptions, ): UseMutationResult => { return useMutation({ mutationFn: (variables: t.TVerifyEmail) => dataService.verifyEmail(variables), ...(options || {}), }); }; /** * Hook for resending verficiation email */ export const useResendVerificationEmail = ( options?: t.ResendVerifcationOptions, ): UseMutationResult => { return useMutation({ mutationFn: (variables: t.TResendVerificationEmail) => dataService.resendVerificationEmail(variables), ...(options || {}), }); }; export const useAcceptTermsMutation = ( options?: t.AcceptTermsMutationOptions, ): UseMutationResult => { const queryClient = useQueryClient(); return useMutation(() => dataService.acceptTerms(), { onSuccess: (data, variables, context) => { queryClient.setQueryData([QueryKeys.userTerms], { termsAccepted: true, }); options?.onSuccess?.(data, variables, context); }, onError: options?.onError, onMutate: options?.onMutate, }); };