import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { toast } from 'sonner'; import api from '@/lib/api'; import type { Connection, ConnectionRequest, UmbralSearchResponse } from '@/types'; export function useConnections() { const queryClient = useQueryClient(); const connectionsQuery = useQuery({ queryKey: ['connections'], queryFn: async () => { const { data } = await api.get('/connections'); return data; }, }); const incomingQuery = useQuery({ queryKey: ['connections', 'incoming'], queryFn: async () => { const { data } = await api.get('/connections/requests/incoming'); return data; }, refetchOnMount: 'always', }); const outgoingQuery = useQuery({ queryKey: ['connections', 'outgoing'], queryFn: async () => { const { data } = await api.get('/connections/requests/outgoing'); return data; }, }); const searchMutation = useMutation({ mutationFn: async (umbralName: string) => { const { data } = await api.post('/connections/search', { umbral_name: umbralName, }); return data; }, }); const sendRequestMutation = useMutation({ mutationFn: async (params: { umbralName: string; personId?: number }) => { const { data } = await api.post('/connections/request', { umbral_name: params.umbralName, ...(params.personId != null && { person_id: params.personId }), }); return data; }, onSuccess: () => { // Fire-and-forget — don't block mutateAsync on query refetches queryClient.invalidateQueries({ queryKey: ['connections'] }); }, }); const respondMutation = useMutation({ mutationFn: async ({ requestId, action }: { requestId: number; action: 'accept' | 'reject' }) => { const { data } = await api.put(`/connections/requests/${requestId}/respond`, { action }); return data; }, onSuccess: (_, variables) => { // Dismiss any lingering Sonner toast for this request toast.dismiss(`connection-request-${variables.requestId}`); // Fire-and-forget — errors here must not surface as mutation failures queryClient.invalidateQueries({ queryKey: ['connections'] }); queryClient.invalidateQueries({ queryKey: ['people'] }); queryClient.invalidateQueries({ queryKey: ['notifications'] }); }, }); const cancelMutation = useMutation({ mutationFn: async (requestId: number) => { const { data } = await api.put(`/connections/requests/${requestId}/cancel`); return data; }, onSuccess: () => { // Fire-and-forget — don't block mutateAsync on query refetches queryClient.invalidateQueries({ queryKey: ['connections'] }); queryClient.invalidateQueries({ queryKey: ['notifications'] }); }, }); const removeConnectionMutation = useMutation({ mutationFn: async (connectionId: number) => { await api.delete(`/connections/${connectionId}`); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['connections'] }); queryClient.invalidateQueries({ queryKey: ['people'] }); queryClient.invalidateQueries({ queryKey: ['calendars', 'shared'] }); queryClient.invalidateQueries({ queryKey: ['calendar-events'] }); }, }); return { connections: connectionsQuery.data ?? [], incomingRequests: incomingQuery.data ?? [], outgoingRequests: outgoingQuery.data ?? [], isLoading: connectionsQuery.isLoading, isLoadingIncoming: incomingQuery.isLoading, search: searchMutation.mutateAsync, isSearching: searchMutation.isPending, sendRequest: sendRequestMutation.mutateAsync, isSending: sendRequestMutation.isPending, respond: respondMutation.mutateAsync, isResponding: respondMutation.isPending, cancelRequest: cancelMutation.mutateAsync, isCancelling: cancelMutation.isPending, removeConnection: removeConnectionMutation.mutateAsync, }; }