Add repost-only mutes (#11223)
Co-authored-by: DS Boyce <260543580+ds-boyce@users.noreply.github.com>
This commit is contained in:
Vendored
+11
-1
@@ -41,6 +41,7 @@ export type {Shadow} from './types'
|
||||
export interface ProfileShadow {
|
||||
followingUri: string | undefined
|
||||
muted: boolean | undefined
|
||||
mutedOnlyReposts: boolean | undefined
|
||||
blockingUri: string | undefined
|
||||
verification: AppBskyActorDefs.VerificationState
|
||||
status: AppBskyActorDefs.StatusView | undefined
|
||||
@@ -243,6 +244,11 @@ export function isProfileShadowApplied<
|
||||
if ('muted' in shadow) {
|
||||
if (profile.viewer?.muted !== shadow.muted) return false
|
||||
}
|
||||
if ('mutedOnlyReposts' in shadow) {
|
||||
if (profile.viewer?.mutedOnlyReposts !== shadow.mutedOnlyReposts) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if ('blockingUri' in shadow) {
|
||||
if (profile.viewer?.blocking !== shadow.blockingUri) return false
|
||||
}
|
||||
@@ -274,13 +280,17 @@ export function mergeShadow<TProfileView extends bsky.profile.AnyProfileView>(
|
||||
? shadow.followingUri
|
||||
: profile.viewer?.following,
|
||||
muted: 'muted' in shadow ? shadow.muted : profile.viewer?.muted,
|
||||
mutedOnlyReposts:
|
||||
'mutedOnlyReposts' in shadow
|
||||
? shadow.mutedOnlyReposts
|
||||
: profile.viewer?.mutedOnlyReposts,
|
||||
blocking:
|
||||
'blockingUri' in shadow ? shadow.blockingUri : profile.viewer?.blocking,
|
||||
activitySubscription:
|
||||
'activitySubscription' in shadow
|
||||
? shadow.activitySubscription
|
||||
: profile.viewer?.activitySubscription,
|
||||
},
|
||||
} satisfies AppBskyActorDefs.ViewerState,
|
||||
verification:
|
||||
'verification' in shadow ? shadow.verification : profile.verification,
|
||||
status:
|
||||
|
||||
@@ -449,9 +449,13 @@ export function useProfileMuteMutationQueue(
|
||||
})
|
||||
|
||||
const queueMute = useCallback(() => {
|
||||
// optimistically update
|
||||
/*
|
||||
* Optimistically update. A full mute replaces any stored repost-only
|
||||
* scope on the server, so clear it here too.
|
||||
*/
|
||||
updateProfileShadow(queryClient, did, {
|
||||
muted: true,
|
||||
mutedOnlyReposts: false,
|
||||
})
|
||||
return queueToggle(true)
|
||||
}, [queryClient, did, queueToggle])
|
||||
@@ -460,6 +464,7 @@ export function useProfileMuteMutationQueue(
|
||||
// optimistically update
|
||||
updateProfileShadow(queryClient, did, {
|
||||
muted: false,
|
||||
mutedOnlyReposts: false,
|
||||
})
|
||||
return queueToggle(false)
|
||||
}, [queryClient, did, queueToggle])
|
||||
@@ -467,6 +472,65 @@ export function useProfileMuteMutationQueue(
|
||||
return [queueMute, queueUnmute] as const
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles a repost-only mute: muting hides just the account's reposts,
|
||||
* unmuting removes the mute entirely. Not applicable when the account is
|
||||
* fully muted (viewer.muted).
|
||||
*/
|
||||
export function useProfileMuteRepostsMutationQueue(
|
||||
profile: Shadow<bsky.profile.AnyProfileView>,
|
||||
) {
|
||||
const ax = useAnalytics()
|
||||
const queryClient = useQueryClient()
|
||||
const did = profile.did
|
||||
const initialMutedOnlyReposts = !!profile.viewer?.mutedOnlyReposts
|
||||
const muteRepostsMutation = useProfileMuteRepostsMutation()
|
||||
const unmuteMutation = useProfileUnmuteMutation()
|
||||
|
||||
const queueToggle = useToggleMutationQueue({
|
||||
initialState: initialMutedOnlyReposts,
|
||||
runMutation: async (_prevMutedOnlyReposts, shouldMute) => {
|
||||
if (shouldMute) {
|
||||
await muteRepostsMutation.mutateAsync({
|
||||
did,
|
||||
})
|
||||
ax.metric('profile:muteReposts', {})
|
||||
return true
|
||||
} else {
|
||||
await unmuteMutation.mutateAsync({
|
||||
did,
|
||||
})
|
||||
ax.metric('profile:unmuteReposts', {})
|
||||
return false
|
||||
}
|
||||
},
|
||||
onSuccess(finalMutedOnlyReposts) {
|
||||
// finalize
|
||||
updateProfileShadow(queryClient, did, {
|
||||
mutedOnlyReposts: finalMutedOnlyReposts,
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
const queueMuteReposts = useCallback(() => {
|
||||
// optimistically update
|
||||
updateProfileShadow(queryClient, did, {
|
||||
mutedOnlyReposts: true,
|
||||
})
|
||||
return queueToggle(true)
|
||||
}, [queryClient, did, queueToggle])
|
||||
|
||||
const queueUnmuteReposts = useCallback(() => {
|
||||
// optimistically update
|
||||
updateProfileShadow(queryClient, did, {
|
||||
mutedOnlyReposts: false,
|
||||
})
|
||||
return queueToggle(false)
|
||||
}, [queryClient, did, queueToggle])
|
||||
|
||||
return [queueMuteReposts, queueUnmuteReposts] as const
|
||||
}
|
||||
|
||||
function useProfileMuteMutation() {
|
||||
const queryClient = useQueryClient()
|
||||
const agent = useAgent()
|
||||
@@ -480,6 +544,19 @@ function useProfileMuteMutation() {
|
||||
})
|
||||
}
|
||||
|
||||
function useProfileMuteRepostsMutation() {
|
||||
const queryClient = useQueryClient()
|
||||
const agent = useAgent()
|
||||
return useMutation<void, Error, {did: string}>({
|
||||
mutationFn: async ({did}) => {
|
||||
await agent.mute(did, {onlyReposts: true})
|
||||
},
|
||||
onSuccess() {
|
||||
void queryClient.invalidateQueries({queryKey: RQKEY_MY_MUTED()})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
function useProfileUnmuteMutation() {
|
||||
const queryClient = useQueryClient()
|
||||
const agent = useAgent()
|
||||
|
||||
Reference in New Issue
Block a user