fix: handle query network failures
67 unmodified lines68697071727374757677727374757677787978 unmodified lines67 unmodified lines receivedNetworkLost = false; receivedNetworkConfirmed = false; checkPromise = checkIsOnline().then((nextIsOnline) => { checkPromise = undefined; if (nextIsOnline && receivedNetworkLost) { isNetworkStateUnclear = true; } if (!nextIsOnline && receivedNetworkConfirmed) { isNetworkStateUnclear = true; }
isNetworkStateUnclear = (nextIsOnline && receivedNetworkLost) || (!nextIsOnline && receivedNetworkConfirmed);
if (!isNetworkStateUnclear) { onlineManager.setOnline(nextIsOnline); } });78 unmodified lines6 unmodified lines7891011111213141555 unmodified lines717273747575767778798081827778798081858687828384858620 unmodified lines10710810911011111211311411811911511611711811912012112212812312412512612712813412913013113213379 unmodified lines6 unmodified linesimport { useBookmarksQuery } from '#/state/queries/bookmarks/useBookmarksQuery';
import { EmptyState } from '#/components/EmptyState';import { List, type ListRenderItemInfo } from '#/components/List/List';import { ListFooter } from '#/components/Lists';import { ListFooter, ListMaybePlaceholder } from '#/components/Lists';import { Post } from '#/components/Post/Post';import { PostFeedLoadingPlaceholder } from '#/components/PostFeed/PostFeedLoadingPlaceholder';import { Text } from '#/components/Text';import * as toast from '#/components/Toast';55 unmodified lines}
/** renders saved posts. */export function BookmarksTab() { const { data, isLoading, isFetchingNextPage, hasNextPage, fetchNextPage, error } = useBookmarksQuery(); const { data, error, fetchNextPage, isError, isFetchingNextPage, isLoading, refetch } = useBookmarksQuery();
const onEndReached = async () => { if (isFetchingNextPage || !hasNextPage || error) { return; } await fetchNextPage(); }; if (isError && !data) { return <ListMaybePlaceholder isLoading={false} isError onRetry={refetch} />; }
const items: ListItem[] = []; if (isLoading) { items.push({ type: 'loading', key: 'loading' }); } else if (!error && data) { if (data) { const bookmarks = data.pages.flatMap((p) => p.bookmarks);
if (bookmarks.length > 0) { for (const bookmark of bookmarks) {20 unmodified lines } } else { items.push({ type: 'empty', key: 'empty' }); } } else if (isLoading) { items.push({ type: 'loading', key: 'loading' }); }
const isEmpty = items.length === 1 && items[0]?.type === 'empty';
return ( <List data={items} estimateHeight={BOOKMARK_ITEM_HEIGHT_ESTIMATE} keyExtractor={keyExtractor} renderItem={renderItem} ListFooterComponent={ <ListFooter border={!isEmpty} border={items.length > 0} error={cleanError(error)} isFetchingNextPage={isFetchingNextPage} onRetry={fetchNextPage} /> } onEndReached={() => void onEndReached()} onEndReached={() => void fetchNextPage()} onEndReachedThreshold={2} /> );}79 unmodified lines3 unmodified lines4567891011128910111213141415161718181920212223242541 unmodified lines3 unmodified lines
/** fetch handler shape shared by the OAuth agent and `@atcute/client`. */export type FetchHandler = (this: void, url: string, init: RequestInit) => Promise<Response>;
/** emits network state events around a fetch-like function. */export function withNetworkEvents<Args extends unknown[]>( fetchFn: (...args: Args) => Promise<Response>,): (...args: Args) => Promise<Response> { return async (...args) => {/** emits network state events around a fetch handler. */export function withNetworkEvents(fetchFn: FetchHandler): FetchHandler { return async (url, init) => { const signal = init.signal;
try { const response = await fetchFn(...args); const response = await fetchFn(url, init); networkConfirmed.emit(); return response; } catch (e) { if (!signal?.aborted) { networkLost.emit(); networkLost.emit(); }
throw e; } };}41 unmodified lines