import { useQuery } from '@tanstack/react-query'; import { useClient } from 'hooks/useClient'; import type { SlskdUserInfo, SlskdUserStatus } from './shared'; /** A peer's presence and profile, as far as either could be reached. */ export type SoulseekUser = { username: string; status: SlskdUserStatus | null; info: SlskdUserInfo | null; }; /** * One peer's presence and profile, cached per username. Selecting a peer you've already looked at paints * from cache instead of blanking the panel back to its empty state and re-asking the network for an * answer it just had — which is what local state did, once per click. */ export function useSoulseekUser(username: string) { const { get } = useClient(); return useQuery({ queryKey: ['soulseek', 'user', username], queryFn: async (): Promise => { const u = encodeURIComponent(username); const [status, info] = await Promise.allSettled([ get(`/soulseek/api/v0/users/${u}/status`), get(`/soulseek/api/v0/users/${u}/info`), ]); // Half an answer is still worth showing — a reachable peer with a private profile answers only one // of the two. Both failing is what actually means "couldn't reach them". if (status.status === 'rejected' && info.status === 'rejected') { throw new Error(`Couldn't reach ${username} — they may be offline.`); } return { username, status: status.status === 'fulfilled' ? status.value : null, info: info.status === 'fulfilled' ? info.value : null, }; }, enabled: !!username, // Presence drifts, but not fast enough to be worth a round trip every time the panel remounts. staleTime: 60_000, // An unreachable peer IS the answer, not a fault to retry: retrying only delays saying so. retry: false, }); }