import { useMutation, useQuery } from '@tanstack/react-query' import { isNil, omitBy } from 'lodash' import { useMemo } from 'react' import { ApiCollection, ApiResource, ConversationResource, ServicesChatGroupIdentifiersResource, ServicesChatPayloadResource, } from '../../types' import { throwResponseError } from '../../utils/response_error' import { ApiClient, useApiClient } from '../use_api_client' interface Props { teamIds?: number[] planId?: number onSuccess?: (conversation: ConversationResource, meta: { created: boolean }) => void } interface TeamAndPlanParams { team_id?: string | null plan_id?: number } export const useFindOrCreateServicesConversation = ({ teamIds, planId, onSuccess }: Props) => { const apiClient = useApiClient() const teamAndPlanParams: TeamAndPlanParams = useMemo( () => buildTeamAndPlanParams(teamIds, planId), [teamIds, planId] ) const { data: selectionHasConversation = false, isLoading: isLoadingConversationCheck } = useQuery({ queryKey: ['conversation-with-group-exists', teamAndPlanParams], queryFn: () => checkIfConversationWithGroupExists(apiClient, teamAndPlanParams), enabled: !!(teamIds?.length || planId), }) const mutation = useMutation({ throwOnError: true, onSuccess: ({ conversation, created }) => { onSuccess?.(conversation, { created }) }, mutationFn: async () => findOrCreateServicesConversation({ apiClient, teamIds: teamIds ?? [], planId }), }) return { ...mutation, selectionHasConversation, isLoadingConversationCheck } } export const findOrCreateServicesConversation = async ({ apiClient, teamIds, planId, }: { apiClient: ApiClient teamIds: number[] planId?: number }): Promise<{ conversation: ConversationResource; created: boolean }> => { const teamAndPlanParams = buildTeamAndPlanParams(teamIds, planId) const foundConversations = await getGroupIdsFromServices(apiClient, teamAndPlanParams) .then(res => res.data.groupIdentifiers) .then(groupIdentifiers => findConversationWithExactTeams(apiClient, groupIdentifiers)) .catch(() => null) const foundConversation = foundConversations?.data[0] if (foundConversation?.id) { return { conversation: foundConversation, created: false } } return getServicesChatConversationPayload({ apiClient, teamIds, planId }) .then(res => res.data.payload) .then(payload => createConversation(apiClient, payload)) .then(res => ({ conversation: res.data, created: true })) .catch(throwResponseError) } export const getServicesChatConversationPayload = ({ apiClient, teamIds, planId, }: { apiClient: ApiClient teamIds: number[] planId?: number }) => { return apiClient.services.get({ url: '/chat', data: { ...buildTeamAndPlanParams(teamIds, planId), fields: { Chat: ['payload'] }, }, }) as Promise> } export const getGroupIdsFromServices = ( apiClient: ApiClient, teamAndPlanParams: TeamAndPlanParams ) => { return apiClient.services.get({ url: '/chat', data: { ...teamAndPlanParams, fields: { Chat: ['group_identifiers'], }, }, }) as Promise> } export const findConversationWithExactTeams = ( apiClient: ApiClient, groupIdentifiers: string[] ) => { return apiClient.chat.get({ url: '/me/conversations', data: { fields: { Conversation: ['title'], }, filter: 'with_exact_groups', gids: groupIdentifiers.join(','), }, }) as Promise> } export const createConversation = (apiClient: ApiClient, payload: string) => { return apiClient.chat.post({ url: '/me/conversations', data: { data: { type: 'Conversation', attributes: { payload } }, }, }) as Promise> } export const findExactTeamConversation = (apiClient: ApiClient, groupIdentifiers: string[]) => { return apiClient.chat.get({ url: '/me/conversations', data: { fields: { Conversation: ['title'], }, filter: 'with_exact_groups', gids: groupIdentifiers.join(','), }, }) as Promise> } export const checkIfConversationWithGroupExists = ( apiClient: ApiClient, teamAndPlanParams: TeamAndPlanParams ) => { return getGroupIdsFromServices(apiClient, teamAndPlanParams) .then(res => res.data.groupIdentifiers) .then(groupIdentifiers => findExactTeamConversation(apiClient, groupIdentifiers)) .then(response => response.data.length > 0) } export const buildTeamAndPlanParams = (teamIds: number[] = [], planId?: number) => { return omitBy( { team_id: teamIds.length ? teamIds.join(',') : null, plan_id: planId, }, isNil ) }