add actual optimistic updates
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import {useCallback, useState} from 'react'
|
||||
import {useCallback} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {
|
||||
type AppBskyGraphGetStarterPacksWithMembership,
|
||||
@@ -7,14 +7,12 @@ import {
|
||||
import {msg, Plural, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {useNavigation} from '@react-navigation/native'
|
||||
import {useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {useRequireEmailVerification} from '#/lib/hooks/useRequireEmailVerification'
|
||||
import {type NavigationProp} from '#/lib/routes/types'
|
||||
import {
|
||||
invalidateActorStarterPacksWithMembershipQuery,
|
||||
useActorStarterPacksWithMembershipsQuery,
|
||||
} from '#/state/queries/actor-starter-packs'
|
||||
import {isNetworkError} from '#/lib/strings/errors'
|
||||
import {logger} from '#/logger'
|
||||
import {useActorStarterPacksWithMembershipsQuery} from '#/state/queries/actor-starter-packs'
|
||||
import {
|
||||
useListMembershipAddMutation,
|
||||
useListMembershipRemoveMutation,
|
||||
@@ -253,50 +251,37 @@ function StarterPackItem({
|
||||
const t = useTheme()
|
||||
const ax = useAnalytics()
|
||||
const {_} = useLingui()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const starterPack = starterPackWithMembership.starterPack
|
||||
const isInPack = !!starterPackWithMembership.listItem
|
||||
|
||||
const [isPendingRefresh, setIsPendingRefresh] = useState(false)
|
||||
const {mutate: addMembership, isPending: isPendingAdd} =
|
||||
useListMembershipAddMutation({
|
||||
onSuccess: () => {
|
||||
Toast.show(_(msg`Added to starter pack`))
|
||||
},
|
||||
onError: err => {
|
||||
if (!isNetworkError(err)) {
|
||||
logger.error('Failed to remove from starter pack', {safeMessage: err})
|
||||
}
|
||||
Toast.show(_(msg`Failed to add to starter pack`), {type: 'error'})
|
||||
},
|
||||
})
|
||||
|
||||
const {mutate: addMembership} = useListMembershipAddMutation({
|
||||
onSuccess: () => {
|
||||
Toast.show(_(msg`Added to starter pack`))
|
||||
// Use a timeout to wait for the appview to update, matching the pattern
|
||||
// in list-memberships.ts
|
||||
setTimeout(() => {
|
||||
invalidateActorStarterPacksWithMembershipQuery({
|
||||
queryClient,
|
||||
did: targetDid,
|
||||
})
|
||||
setIsPendingRefresh(false)
|
||||
}, 1e3)
|
||||
},
|
||||
onError: () => {
|
||||
Toast.show(_(msg`Failed to add to starter pack`), 'xmark')
|
||||
setIsPendingRefresh(false)
|
||||
},
|
||||
})
|
||||
const {mutate: removeMembership, isPending: isPendingRemove} =
|
||||
useListMembershipRemoveMutation({
|
||||
onSuccess: () => {
|
||||
Toast.show(_(msg`Removed from starter pack`))
|
||||
},
|
||||
onError: err => {
|
||||
if (!isNetworkError(err)) {
|
||||
logger.error('Failed to remove from starter pack', {safeMessage: err})
|
||||
}
|
||||
Toast.show(_(msg`Failed to remove from starter pack`), {type: 'error'})
|
||||
},
|
||||
})
|
||||
|
||||
const {mutate: removeMembership} = useListMembershipRemoveMutation({
|
||||
onSuccess: () => {
|
||||
Toast.show(_(msg`Removed from starter pack`))
|
||||
// Use a timeout to wait for the appview to update, matching the pattern
|
||||
// in list-memberships.ts
|
||||
setTimeout(() => {
|
||||
invalidateActorStarterPacksWithMembershipQuery({
|
||||
queryClient,
|
||||
did: targetDid,
|
||||
})
|
||||
setIsPendingRefresh(false)
|
||||
}, 1e3)
|
||||
},
|
||||
onError: () => {
|
||||
Toast.show(_(msg`Failed to remove from starter pack`), 'xmark')
|
||||
setIsPendingRefresh(false)
|
||||
},
|
||||
})
|
||||
const isPending = isPendingAdd || isPendingRemove
|
||||
|
||||
const handleToggleMembership = () => {
|
||||
if (!starterPack.list?.uri || isPending) return
|
||||
@@ -313,7 +298,6 @@ function StarterPackItem({
|
||||
} else {
|
||||
if (!starterPackWithMembership.listItem?.uri) {
|
||||
console.error('Cannot remove: missing membership URI')
|
||||
setIsPendingRefresh(false)
|
||||
return
|
||||
}
|
||||
removeMembership({
|
||||
@@ -379,8 +363,9 @@ function StarterPackItem({
|
||||
label={isInPack ? _(msg`Remove`) : _(msg`Add`)}
|
||||
color={isInPack ? 'secondary' : 'primary_subtle'}
|
||||
size="tiny"
|
||||
disabled={isPendingRefresh}
|
||||
disabled={isPending}
|
||||
onPress={handleToggleMembership}>
|
||||
{isPending && <ButtonIcon icon={Loader} />}
|
||||
<ButtonText>
|
||||
{isInPack ? <Trans>Remove</Trans> : <Trans>Add</Trans>}
|
||||
</ButtonText>
|
||||
|
||||
@@ -1,13 +1,4 @@
|
||||
import {
|
||||
type AppBskyGraphGetActorStarterPacks,
|
||||
type AppBskyGraphGetStarterPacksWithMembership,
|
||||
} from '@atproto/api'
|
||||
import {
|
||||
type InfiniteData,
|
||||
type QueryClient,
|
||||
type QueryKey,
|
||||
useInfiniteQuery,
|
||||
} from '@tanstack/react-query'
|
||||
import {type QueryClient, useInfiniteQuery} from '@tanstack/react-query'
|
||||
|
||||
import {useAgent} from '#/state/session'
|
||||
|
||||
@@ -28,13 +19,7 @@ export function useActorStarterPacksQuery({
|
||||
}) {
|
||||
const agent = useAgent()
|
||||
|
||||
return useInfiniteQuery<
|
||||
AppBskyGraphGetActorStarterPacks.OutputSchema,
|
||||
Error,
|
||||
InfiniteData<AppBskyGraphGetActorStarterPacks.OutputSchema>,
|
||||
QueryKey,
|
||||
string | undefined
|
||||
>({
|
||||
return useInfiniteQuery({
|
||||
queryKey: RQKEY(did),
|
||||
queryFn: async ({pageParam}: {pageParam?: string}) => {
|
||||
const res = await agent.app.bsky.graph.getActorStarterPacks({
|
||||
@@ -59,13 +44,7 @@ export function useActorStarterPacksWithMembershipsQuery({
|
||||
}) {
|
||||
const agent = useAgent()
|
||||
|
||||
return useInfiniteQuery<
|
||||
AppBskyGraphGetStarterPacksWithMembership.OutputSchema,
|
||||
Error,
|
||||
InfiniteData<AppBskyGraphGetStarterPacksWithMembership.OutputSchema>,
|
||||
QueryKey,
|
||||
string | undefined
|
||||
>({
|
||||
return useInfiniteQuery({
|
||||
queryKey: RQKEY_WITH_MEMBERSHIP(did),
|
||||
queryFn: async ({pageParam}: {pageParam?: string}) => {
|
||||
const res = await agent.app.bsky.graph.getStarterPacksWithMembership({
|
||||
|
||||
@@ -14,12 +14,22 @@
|
||||
* -prf
|
||||
*/
|
||||
|
||||
import {AtUri} from '@atproto/api'
|
||||
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'
|
||||
import {
|
||||
type AppBskyActorDefs,
|
||||
type AppBskyGraphGetStarterPacksWithMembership,
|
||||
AtUri,
|
||||
} from '@atproto/api'
|
||||
import {
|
||||
type InfiniteData,
|
||||
useMutation,
|
||||
useQuery,
|
||||
useQueryClient,
|
||||
} from '@tanstack/react-query'
|
||||
|
||||
import {STALE} from '#/state/queries'
|
||||
import {RQKEY as LIST_MEMBERS_RQKEY} from '#/state/queries/list-members'
|
||||
import {useAgent, useSession} from '#/state/session'
|
||||
import {RQKEY_WITH_MEMBERSHIP as STARTER_PACKS_WITH_MEMBERSHIPS_RKEY} from './actor-starter-packs'
|
||||
|
||||
// sanity limit is SANITY_PAGE_LIMIT*PAGE_SIZE total records
|
||||
const SANITY_PAGE_LIMIT = 1000
|
||||
@@ -123,7 +133,7 @@ export function useListMembershipAddMutation({
|
||||
// -prf
|
||||
return res
|
||||
},
|
||||
onSuccess: (data, variables) => {
|
||||
onSuccess: async (data, variables) => {
|
||||
// manually update the cache; a refetch is too expensive
|
||||
let memberships = queryClient.getQueryData<ListMembersip[]>(RQKEY())
|
||||
if (memberships) {
|
||||
@@ -151,6 +161,42 @@ export function useListMembershipAddMutation({
|
||||
queryKey: LIST_MEMBERS_RQKEY(variables.listUri),
|
||||
})
|
||||
}, 1e3)
|
||||
|
||||
// update WITH_MEMBERSHIPS query
|
||||
const subject = await agent
|
||||
.getProfile({actor: variables.actorDid})
|
||||
.then(res => res.data)
|
||||
|
||||
if (subject) {
|
||||
queryClient.setQueryData<
|
||||
InfiniteData<AppBskyGraphGetStarterPacksWithMembership.OutputSchema>
|
||||
>(STARTER_PACKS_WITH_MEMBERSHIPS_RKEY(variables.actorDid), old => {
|
||||
if (!old) return old
|
||||
|
||||
return {
|
||||
...old,
|
||||
pages: old.pages.map(page => ({
|
||||
...page,
|
||||
starterPacksWithMembership: page.starterPacksWithMembership.map(
|
||||
list => {
|
||||
if (list.starterPack.list?.uri === variables.listUri) {
|
||||
return {
|
||||
...list,
|
||||
listItem: {
|
||||
uri: data.uri,
|
||||
subject: subject as AppBskyActorDefs.ProfileView,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return list
|
||||
},
|
||||
),
|
||||
})),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onSuccess?.(data)
|
||||
},
|
||||
onError,
|
||||
@@ -206,6 +252,32 @@ export function useListMembershipRemoveMutation({
|
||||
queryKey: LIST_MEMBERS_RQKEY(variables.listUri),
|
||||
})
|
||||
}, 1e3)
|
||||
|
||||
queryClient.setQueryData<
|
||||
InfiniteData<AppBskyGraphGetStarterPacksWithMembership.OutputSchema>
|
||||
>(STARTER_PACKS_WITH_MEMBERSHIPS_RKEY(variables.actorDid), old => {
|
||||
if (!old) return old
|
||||
|
||||
return {
|
||||
...old,
|
||||
pages: old.pages.map(page => ({
|
||||
...page,
|
||||
starterPacksWithMembership: page.starterPacksWithMembership.map(
|
||||
list => {
|
||||
if (list.starterPack.list?.uri === variables.listUri) {
|
||||
return {
|
||||
...list,
|
||||
listItem: undefined,
|
||||
}
|
||||
}
|
||||
|
||||
return list
|
||||
},
|
||||
),
|
||||
})),
|
||||
}
|
||||
})
|
||||
|
||||
onSuccess?.(data)
|
||||
},
|
||||
onError,
|
||||
|
||||
Reference in New Issue
Block a user