Bluesky app fork with some witchin' additions 馃挮
at readme-update 159 lines 4.0 kB view raw
1import { 2 type $Typed, 3 type AppBskyBookmarkGetBookmarks, 4 AppBskyFeedDefs, 5 AtUri, 6} from '@atproto/api' 7import { 8 type InfiniteData, 9 type QueryClient, 10 type QueryKey, 11 useInfiniteQuery, 12} from '@tanstack/react-query' 13 14import { 15 didOrHandleUriMatches, 16 embedViewRecordToPostView, 17 getEmbeddedPost, 18} from '#/state/queries/util' 19import {useAgent} from '#/state/session' 20import * as bsky from '#/types/bsky' 21 22export const bookmarksQueryKeyRoot = 'bookmarks' 23export const createBookmarksQueryKey = () => [bookmarksQueryKeyRoot] 24 25export function useBookmarksQuery() { 26 const agent = useAgent() 27 28 return useInfiniteQuery< 29 AppBskyBookmarkGetBookmarks.OutputSchema, 30 Error, 31 InfiniteData<AppBskyBookmarkGetBookmarks.OutputSchema>, 32 QueryKey, 33 string | undefined 34 >({ 35 queryKey: createBookmarksQueryKey(), 36 async queryFn({pageParam}) { 37 const res = await agent.app.bsky.bookmark.getBookmarks({ 38 cursor: pageParam, 39 }) 40 return res.data 41 }, 42 initialPageParam: undefined, 43 getNextPageParam: lastPage => lastPage.cursor, 44 }) 45} 46 47export async function truncateAndInvalidate(qc: QueryClient) { 48 qc.setQueriesData<InfiniteData<AppBskyBookmarkGetBookmarks.OutputSchema>>( 49 {queryKey: [bookmarksQueryKeyRoot]}, 50 data => { 51 if (data) { 52 return { 53 pageParams: data.pageParams.slice(0, 1), 54 pages: data.pages.slice(0, 1), 55 } 56 } 57 return data 58 }, 59 ) 60 return qc.invalidateQueries({queryKey: [bookmarksQueryKeyRoot]}) 61} 62 63export async function optimisticallySaveBookmark( 64 qc: QueryClient, 65 post: AppBskyFeedDefs.PostView, 66) { 67 qc.setQueriesData<InfiniteData<AppBskyBookmarkGetBookmarks.OutputSchema>>( 68 { 69 queryKey: [bookmarksQueryKeyRoot], 70 }, 71 data => { 72 if (!data) return data 73 return { 74 ...data, 75 pages: data.pages.map((page, index) => { 76 if (index === 0) { 77 post.$type = 'app.bsky.feed.defs#postView' 78 return { 79 ...page, 80 bookmarks: [ 81 { 82 createdAt: new Date().toISOString(), 83 subject: { 84 uri: post.uri, 85 cid: post.cid, 86 }, 87 item: post as $Typed<AppBskyFeedDefs.PostView>, 88 }, 89 ...page.bookmarks, 90 ], 91 } 92 } 93 return page 94 }), 95 } 96 }, 97 ) 98} 99 100export async function optimisticallyDeleteBookmark( 101 qc: QueryClient, 102 {uri}: {uri: string}, 103) { 104 qc.setQueriesData<InfiniteData<AppBskyBookmarkGetBookmarks.OutputSchema>>( 105 { 106 queryKey: [bookmarksQueryKeyRoot], 107 }, 108 data => { 109 if (!data) return data 110 return { 111 ...data, 112 pages: data.pages.map(page => { 113 return { 114 ...page, 115 bookmarks: page.bookmarks.filter(b => b.subject.uri !== uri), 116 } 117 }), 118 } 119 }, 120 ) 121} 122 123export function* findAllPostsInQueryData( 124 queryClient: QueryClient, 125 uri: string, 126): Generator<AppBskyFeedDefs.PostView, undefined> { 127 const queryDatas = queryClient.getQueriesData< 128 InfiniteData<AppBskyBookmarkGetBookmarks.OutputSchema> 129 >({ 130 queryKey: [bookmarksQueryKeyRoot], 131 }) 132 const atUri = new AtUri(uri) 133 134 for (const [_queryKey, queryData] of queryDatas) { 135 if (!queryData?.pages) { 136 continue 137 } 138 for (const page of queryData?.pages) { 139 for (const bookmark of page.bookmarks) { 140 if ( 141 !bsky.dangerousIsType<AppBskyFeedDefs.PostView>( 142 bookmark.item, 143 AppBskyFeedDefs.isPostView, 144 ) 145 ) 146 continue 147 148 if (didOrHandleUriMatches(atUri, bookmark.item)) { 149 yield bookmark.item 150 } 151 152 const quotedPost = getEmbeddedPost(bookmark.item.embed) 153 if (quotedPost && didOrHandleUriMatches(atUri, quotedPost)) { 154 yield embedViewRecordToPostView(quotedPost) 155 } 156 } 157 } 158 } 159}