import { useMutation, useQueryClient } from '@tanstack/react-query' import { useState } from 'react' import { Alert } from 'react-native' import { ApiResource, ConversationResource } from '../types' import { transformGetToPost } from '../utils/client/request_helpers' import { Haptic } from '../utils/native_adapters' import { getConversationsRequestArgs } from '../utils/request/conversation' import { useApiClient } from './use_api_client' import { useCurrentPersonCache } from './use_current_person' import { getRequestQueryKey, SuspenseGetQueryOptions, useSuspenseGet } from './use_suspense_api' export const getConversationRequestArgs = ({ conversation_id }: { conversation_id: number }) => ({ url: `/me/conversations/${conversation_id}`, data: { fields: { Conversation: [ 'analytics_metadata', 'created_at', 'badges', 'conversation_membership', 'conversation_preview', 'gender_option', 'groups', 'last_message_author_id', 'last_message_author_name', 'last_message_created_at', 'last_message_text_preview', 'latest_read_message_sort_key', 'preview_avatar_urls', 'custom_avatar_type', 'custom_avatar_key', 'custom_avatar_color', 'custom_avatar_image_url', 'direct_message', 'disabled', 'disabled_reason', 'disabled_message', 'member_ability', 'muted', 'replies_disabled', 'title', 'unread_count', 'unread_reaction', 'updated_at', ], AnalyticsMetadata: ['metadata'], MemberAbility: [ 'can_update', 'can_delete', 'leader', 'can_reply', 'can_delete_non_authored_messages', 'can_message_available_members', 'can_archive', 'can_unarchive', ], ConversationMembership: [ 'last_read_message_sort_key', 'notification_level', 'notification_level_description', 'notification_level_options', 'muted', ], ConversationBadge: ['app_name', 'pco_resource_type', 'text'], Group: ['type', 'id', 'links', 'name', 'source_app_name', 'source_type'], }, include: [ 'badges', 'conversation_membership', 'member_ability', 'groups', 'analytics_metadata', ], }, }) export const useConversation = ( { conversation_id }: { conversation_id: number }, options?: SuspenseGetQueryOptions ) => { const args = getConversationRequestArgs({ conversation_id }) return useSuspenseGet(args, options) } export const useConversationMute = ({ conversation_id }: { conversation_id: number }) => { const apiClient = useApiClient() const queryClient = useQueryClient() const requestArgs = getConversationRequestArgs({ conversation_id }) const queryKey = getRequestQueryKey(requestArgs) const { data: conversation } = useConversation({ conversation_id }) const [value, setValue] = useState(conversation.muted) const { mutate: setMuted, ...mutation } = useMutation({ onMutate: async (muted: boolean) => { return queryClient.setQueryData>(queryKey, prev => { if (!prev?.data) return prev setValue(muted) prev.data.muted = muted if (prev.data.conversationMembership) { prev.data.conversationMembership.muted = muted } return prev }) }, mutationKey: ['muteConversation'], mutationFn: async (muted: boolean) => { const action = muted ? 'mute' : 'unmute' return apiClient.chat.post>({ url: `/me/conversations/${conversation_id}/${action}`, data: { data: { type: '', attributes: {} }, fields: { Conversation: 'muted' } }, }) }, onSuccess: (response: ApiResource) => { queryClient.invalidateQueries({ queryKey: ['/me/conversations'] }) queryClient.setQueryData>(queryKey, prev => { if (!prev?.data) return prev // Posting to the mute action endpoint can't return all the fields // so we need to set only the fields we require prev.data.muted = response.data.muted if (prev.data.conversationMembership) { prev.data.conversationMembership.muted = response.data.muted } setValue(response.data.muted) return prev }) }, }) return { muted: value, setMuted, ...mutation } } export const useConversationUpdate = ({ conversation_id }: { conversation_id: number }) => { const apiClient = useApiClient() const queryClient = useQueryClient() const requestArgs = getConversationRequestArgs({ conversation_id }) const queryKey = getRequestQueryKey(requestArgs) return useMutation({ onMutate: async (update: Partial) => { queryClient.setQueryData>(queryKey, prev => { if (prev?.data) { prev.data = { ...prev.data, ...update, } } return prev }) }, mutationKey: ['mutateConversation'], mutationFn: async (update: Partial) => { const postArgs = transformGetToPost(requestArgs).data return apiClient.chat.patch>({ url: `/me/conversations/${conversation_id}/`, data: { data: { type: '', attributes: update }, ...postArgs }, }) }, onSuccess: response => { queryClient.setQueryData>(queryKey, () => response) }, }) } export const useConversationDelete = ({ conversation_id }: { conversation_id: number }) => { const apiClient = useApiClient() const queryClient = useQueryClient() const { url } = getConversationsRequestArgs() return useMutation({ mutationKey: ['deleteConversation'], mutationFn: async () => { return apiClient.chat.delete({ url: `/me/conversations/${conversation_id}`, }) }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: [url] }) Haptic.notificationSuccess() }, }) } export const useConversationArchive = ({ conversation_id }: { conversation_id: number }) => { const apiClient = useApiClient() const queryClient = useQueryClient() const currentPersonCache = useCurrentPersonCache() const conversationQueryKey = getRequestQueryKey(getConversationRequestArgs({ conversation_id })) const { url } = getConversationsRequestArgs() const { mutate: setArchived, ...mutation } = useMutation({ mutationKey: ['archiveConversation'], mutationFn: async (archived: boolean) => { const action = archived ? 'archive' : 'unarchive' return apiClient.chat.post({ url: `/me/conversations/${conversation_id}/${action}`, data: { data: { type: 'Conversation', attributes: {} } }, }) }, onSuccess: (_response, archived) => { Haptic.notificationSuccess() if (archived) currentPersonCache.update({ canBrowseArchivedConversations: true }) queryClient.invalidateQueries({ queryKey: [url] }) return queryClient.invalidateQueries({ queryKey: conversationQueryKey }) }, onError: (_error, archived) => { Alert.alert( 'Oops', `Couldn't ${archived ? 'archive' : 'unarchive'} this conversation. Please try again.` ) }, }) return { setArchived, ...mutation } } export const useConversationDisableReplies = ({ conversation_id }: { conversation_id: number }) => { const apiClient = useApiClient() const queryClient = useQueryClient() const requestArgs = getConversationRequestArgs({ conversation_id }) const queryKey = getRequestQueryKey(requestArgs) const { data: conversation } = useConversation({ conversation_id }) const [value, setValue] = useState(conversation.repliesDisabled) const { mutate: setRepliesDisabled, ...mutation } = useMutation({ onMutate: async (repliesDisabled: boolean) => { return queryClient.setQueryData>(queryKey, prev => { if (!prev?.data) return prev setValue(repliesDisabled) prev.data.repliesDisabled = repliesDisabled return prev }) }, mutationKey: ['disableRepliesConversation'], mutationFn: async (repliesDisabled: boolean) => { return apiClient.chat.patch>({ url: `/me/conversations/${conversation_id}`, data: { data: { type: 'Conversation', attributes: { replies_disabled: repliesDisabled, }, }, }, }) }, onSuccess: (response: ApiResource) => { queryClient.setQueryData>(queryKey, prev => { if (!prev?.data) return prev prev.data.repliesDisabled = response.data.repliesDisabled setValue(response.data.repliesDisabled) return prev }) }, }) return { repliesDisabled: value, setRepliesDisabled, ...mutation } }