Start to break apart queries for better composition
This commit is contained in:
@@ -2,7 +2,10 @@ import {AppBskyFeedThreadgate, AtUri, BskyAgent} from '@atproto/api'
|
|||||||
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'
|
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {networkRetry} from '#/lib/async/retry'
|
import {networkRetry} from '#/lib/async/retry'
|
||||||
import {mergeThreadgateRecords} from '#/state/queries/threadgate/util'
|
import {
|
||||||
|
createThreadgateRecord,
|
||||||
|
mergeThreadgateRecords,
|
||||||
|
} from '#/state/queries/threadgate/util'
|
||||||
import {useAgent} from '#/state/session'
|
import {useAgent} from '#/state/session'
|
||||||
|
|
||||||
export * from '#/state/queries/threadgate/types'
|
export * from '#/state/queries/threadgate/types'
|
||||||
@@ -47,6 +50,36 @@ export function useThreadgateRecordQuery({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getThreadgateRecord({
|
||||||
|
agent,
|
||||||
|
postUri,
|
||||||
|
}: {
|
||||||
|
agent: BskyAgent
|
||||||
|
postUri: string
|
||||||
|
}): Promise<AppBskyFeedThreadgate.Record | undefined> {
|
||||||
|
const postUrip = new AtUri(postUri)
|
||||||
|
|
||||||
|
try {
|
||||||
|
const {data} = await networkRetry(2, () =>
|
||||||
|
agent.api.com.atproto.repo.getRecord({
|
||||||
|
repo: agent.session!.did,
|
||||||
|
collection: 'app.bsky.feed.threadgate',
|
||||||
|
rkey: postUrip.rkey,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
if (data.value && AppBskyFeedThreadgate.isRecord(data.value)) {
|
||||||
|
return data.value
|
||||||
|
}
|
||||||
|
} catch (e: any) {
|
||||||
|
if (e.message.includes(`Could not locate record:`)) {
|
||||||
|
return undefined
|
||||||
|
} else {
|
||||||
|
throw new Error(`Failed to get threadgate record`, {cause: e})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function createThreadgate({
|
export async function createThreadgate({
|
||||||
agent,
|
agent,
|
||||||
postUri,
|
postUri,
|
||||||
@@ -100,6 +133,34 @@ export async function createThreadgate({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function overwriteThreadgateRecord({
|
||||||
|
agent,
|
||||||
|
postUri,
|
||||||
|
threadgate,
|
||||||
|
}: {
|
||||||
|
agent: BskyAgent
|
||||||
|
postUri: string
|
||||||
|
threadgate: AppBskyFeedThreadgate.Record
|
||||||
|
}) {
|
||||||
|
const postUrip = new AtUri(postUri)
|
||||||
|
const record: AppBskyFeedThreadgate.Record = {
|
||||||
|
$type: 'app.bsky.feed.threadgate',
|
||||||
|
post: postUri,
|
||||||
|
allow: threadgate.allow || [],
|
||||||
|
hiddenReplies: threadgate.hiddenReplies || [],
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
}
|
||||||
|
|
||||||
|
await networkRetry(2, () =>
|
||||||
|
agent.api.com.atproto.repo.putRecord({
|
||||||
|
repo: agent.session!.did,
|
||||||
|
collection: 'app.bsky.feed.threadgate',
|
||||||
|
rkey: postUrip.rkey,
|
||||||
|
record,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export function useCreateThreadgateMutation() {
|
export function useCreateThreadgateMutation() {
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
@@ -125,3 +186,64 @@ export function useCreateThreadgateMutation() {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useToggleReplyVisibilityMutation() {
|
||||||
|
const agent = useAgent()
|
||||||
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: async ({
|
||||||
|
postUri,
|
||||||
|
replyUri,
|
||||||
|
action,
|
||||||
|
}: {
|
||||||
|
postUri: string
|
||||||
|
replyUri: string
|
||||||
|
action: 'hide' | 'show'
|
||||||
|
}) => {
|
||||||
|
const prev = await getThreadgateRecord({
|
||||||
|
agent,
|
||||||
|
postUri,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (prev) {
|
||||||
|
let threadgate = prev
|
||||||
|
|
||||||
|
if (action === 'hide') {
|
||||||
|
threadgate = mergeThreadgateRecords(prev, {
|
||||||
|
hiddenReplies: [replyUri],
|
||||||
|
})
|
||||||
|
} else if (action === 'show') {
|
||||||
|
threadgate = {
|
||||||
|
...prev,
|
||||||
|
hiddenReplies:
|
||||||
|
prev.hiddenReplies?.filter(uri => uri !== replyUri) || [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await overwriteThreadgateRecord({
|
||||||
|
agent,
|
||||||
|
postUri,
|
||||||
|
threadgate,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
if (action === 'hide') {
|
||||||
|
const threadgate = createThreadgateRecord({
|
||||||
|
post: postUri,
|
||||||
|
hiddenReplies: [replyUri],
|
||||||
|
})
|
||||||
|
await overwriteThreadgateRecord({
|
||||||
|
agent,
|
||||||
|
postUri,
|
||||||
|
threadgate,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onSuccess() {
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: [threadgateRecordQueryKeyRoot],
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -83,11 +83,25 @@ export function mergeThreadgateRecords(
|
|||||||
new Set([...(prev.hiddenReplies || []), ...(next.hiddenReplies || [])]),
|
new Set([...(prev.hiddenReplies || []), ...(next.hiddenReplies || [])]),
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return createThreadgateRecord({
|
||||||
$type: 'app.bsky.feed.threadgate',
|
|
||||||
post: prev.post,
|
post: prev.post,
|
||||||
allow,
|
allow,
|
||||||
createdAt: new Date().toISOString(),
|
|
||||||
hiddenReplies,
|
hiddenReplies,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createThreadgateRecord(
|
||||||
|
threadgate: Partial<AppBskyFeedThreadgate.Record>,
|
||||||
|
): AppBskyFeedThreadgate.Record {
|
||||||
|
if (!threadgate.post) {
|
||||||
|
throw new Error('Cannot create a threadgate record without a post URI')
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
$type: 'app.bsky.feed.threadgate',
|
||||||
|
post: threadgate.post,
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
allow: threadgate.allow || [],
|
||||||
|
hiddenReplies: threadgate.hiddenReplies || [],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ import {
|
|||||||
usePostDeleteMutation,
|
usePostDeleteMutation,
|
||||||
useThreadMuteMutationQueue,
|
useThreadMuteMutationQueue,
|
||||||
} from '#/state/queries/post'
|
} from '#/state/queries/post'
|
||||||
import {useCreateThreadgateMutation} from '#/state/queries/threadgate'
|
import {useToggleReplyVisibilityMutation} from '#/state/queries/threadgate'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {getCurrentRoute} from 'lib/routes/helpers'
|
import {getCurrentRoute} from 'lib/routes/helpers'
|
||||||
import {shareUrl} from 'lib/sharing'
|
import {shareUrl} from 'lib/sharing'
|
||||||
@@ -107,7 +107,8 @@ let PostDropdownBtn = ({
|
|||||||
const loggedOutWarningPromptControl = useDialogControl()
|
const loggedOutWarningPromptControl = useDialogControl()
|
||||||
const embedPostControl = useDialogControl()
|
const embedPostControl = useDialogControl()
|
||||||
const sendViaChatControl = useDialogControl()
|
const sendViaChatControl = useDialogControl()
|
||||||
const {mutateAsync: createThreadgate} = useCreateThreadgateMutation()
|
const {mutateAsync: toggleReplyVisibility} =
|
||||||
|
useToggleReplyVisibilityMutation()
|
||||||
|
|
||||||
const postUri = post.uri
|
const postUri = post.uri
|
||||||
const postCid = post.cid
|
const postCid = post.cid
|
||||||
@@ -402,16 +403,17 @@ let PostDropdownBtn = ({
|
|||||||
{!isAuthor && !isPostHidden && rootPostUri && (
|
{!isAuthor && !isPostHidden && rootPostUri && (
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
testID="postDropdownHideBtn"
|
testID="postDropdownHideBtn"
|
||||||
label={_(msg`Hide reply`)}
|
label={_(msg`Hide reply for everyone`)}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
createThreadgate({
|
toggleReplyVisibility({
|
||||||
postUri: rootPostUri,
|
postUri: rootPostUri,
|
||||||
threadgate: {
|
replyUri: postUri,
|
||||||
hiddenReplies: [postUri],
|
action: 'hide',
|
||||||
},
|
|
||||||
})
|
})
|
||||||
}}>
|
}}>
|
||||||
<Menu.ItemText>{_(msg`Hide reply`)}</Menu.ItemText>
|
<Menu.ItemText>
|
||||||
|
{_(msg`Hide reply for everyone`)}
|
||||||
|
</Menu.ItemText>
|
||||||
<Menu.ItemIcon icon={EyeSlash} position="right" />
|
<Menu.ItemIcon icon={EyeSlash} position="right" />
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user