diff options
author | Samuel Newman <mozzius@protonmail.com> | 2024-09-27 22:50:32 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-09-28 00:50:32 +0300 |
commit | 4b5d6e6efb09a714d82e2093dec39c85400a2de6 (patch) | |
tree | 981d0e08b30549234e02be49dbb190e55740556f /src/state/queries/pinned-post.ts | |
parent | f68b15219fd02e23d965015201400138ed69d59d (diff) | |
download | voidsky-4b5d6e6efb09a714d82e2093dec39c85400a2de6.tar.zst |
Pinned posts (#5055)
* add to dropdown menu * use normal profile mutation hook * add pin as reason * request pins * shadow update * rm logs * get prev pinned from getProfile * fix toasts * invalidate after appview ready * don't mutate params * rm log * use checkCommited rather than manual whenAppViewReady * move to mutation * even more optimistic optimistic update * allow pins in `posts_and_author_threads` * update @atproto/api * add reasonPin type * fix strange type error in unrelated query * another missing type
Diffstat (limited to 'src/state/queries/pinned-post.ts')
-rw-r--r-- | src/state/queries/pinned-post.ts | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/src/state/queries/pinned-post.ts b/src/state/queries/pinned-post.ts new file mode 100644 index 000000000..7e2c8ee79 --- /dev/null +++ b/src/state/queries/pinned-post.ts @@ -0,0 +1,87 @@ +import {msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {useMutation, useQueryClient} from '@tanstack/react-query' + +import {logger} from '#/logger' +import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed' +import * as Toast from '#/view/com/util/Toast' +import {updatePostShadow} from '../cache/post-shadow' +import {useAgent, useSession} from '../session' +import {useProfileUpdateMutation} from './profile' + +export function usePinnedPostMutation() { + const {_} = useLingui() + const {currentAccount} = useSession() + const agent = useAgent() + const queryClient = useQueryClient() + const {mutateAsync: profileUpdateMutate} = useProfileUpdateMutation() + + return useMutation({ + mutationFn: async ({ + postUri, + postCid, + action, + }: { + postUri: string + postCid: string + action: 'pin' | 'unpin' + }) => { + const pinCurrentPost = action === 'pin' + let prevPinnedPost: string | undefined + try { + updatePostShadow(queryClient, postUri, {pinned: pinCurrentPost}) + + // get the currently pinned post so we can optimistically remove the pin from it + if (!currentAccount) throw new Error('Not logged in') + const {data: profile} = await agent.getProfile({ + actor: currentAccount.did, + }) + prevPinnedPost = profile.pinnedPost?.uri + if (prevPinnedPost && prevPinnedPost !== postUri) { + updatePostShadow(queryClient, prevPinnedPost, {pinned: false}) + } + + await profileUpdateMutate({ + profile, + updates: existing => { + existing.pinnedPost = pinCurrentPost + ? {uri: postUri, cid: postCid} + : undefined + return existing + }, + checkCommitted: res => + pinCurrentPost + ? res.data.pinnedPost?.uri === postUri + : !res.data.pinnedPost, + }) + + if (pinCurrentPost) { + Toast.show(_(msg`Post pinned`)) + } else { + Toast.show(_(msg`Post unpinned`)) + } + + queryClient.invalidateQueries({ + queryKey: FEED_RQKEY( + `author|${currentAccount.did}|posts_and_author_threads`, + ), + }) + queryClient.invalidateQueries({ + queryKey: FEED_RQKEY( + `author|${currentAccount.did}|posts_with_replies`, + ), + }) + } catch (e: any) { + Toast.show(_(msg`Failed to pin post`)) + logger.error('Failed to pin post', {message: String(e)}) + // revert optimistic update + updatePostShadow(queryClient, postUri, { + pinned: !pinCurrentPost, + }) + if (prevPinnedPost && prevPinnedPost !== postUri) { + updatePostShadow(queryClient, prevPinnedPost, {pinned: true}) + } + } + }, + }) +} |