Previous fix (2139ea8) caused regression: staleTime:0 nuked cache on every mount, isLoadingIncoming disabled buttons during cold-cache fetch. Changes: - Remove staleTime:0 (keep refetchOnMount:'always' for background refresh) - Revert button gate to pendingRequestIds.has() only (no is_read gate) - Remove isLoadingIncoming from disabled prop and spinner condition - Add 409-as-success handling to ConnectionRequestCard (People tab) - Use axios.isAxiosError() instead of err:any in all 3 catch blocks - Add markRead() call to 409 branch so notifications clear properly Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
111 lines
3.8 KiB
TypeScript
111 lines
3.8 KiB
TypeScript
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<Connection[]>('/connections');
|
|
return data;
|
|
},
|
|
});
|
|
|
|
const incomingQuery = useQuery({
|
|
queryKey: ['connections', 'incoming'],
|
|
queryFn: async () => {
|
|
const { data } = await api.get<ConnectionRequest[]>('/connections/requests/incoming');
|
|
return data;
|
|
},
|
|
refetchOnMount: 'always',
|
|
});
|
|
|
|
const outgoingQuery = useQuery({
|
|
queryKey: ['connections', 'outgoing'],
|
|
queryFn: async () => {
|
|
const { data } = await api.get<ConnectionRequest[]>('/connections/requests/outgoing');
|
|
return data;
|
|
},
|
|
});
|
|
|
|
const searchMutation = useMutation({
|
|
mutationFn: async (umbralName: string) => {
|
|
const { data } = await api.post<UmbralSearchResponse>('/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'] });
|
|
},
|
|
});
|
|
|
|
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,
|
|
};
|
|
}
|