loading state

This commit is contained in:
Chenyu Huang
2025-08-19 16:29:18 -07:00
parent e32f280f47
commit 68e0a78f70
3 changed files with 54 additions and 42 deletions
+45 -22
View File
@@ -26,6 +26,7 @@ import {atoms as a, useTheme} from '#/alf'
import {Button, ButtonIcon, ButtonText} from '#/components/Button' import {Button, ButtonIcon, ButtonText} from '#/components/Button'
import * as Dialog from '#/components/Dialog' import * as Dialog from '#/components/Dialog'
import {Divider} from '#/components/Divider' import {Divider} from '#/components/Divider'
import {Loader} from '#/components/Loader'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
import * as bsky from '#/types/bsky' import * as bsky from '#/types/bsky'
import {PlusLarge_Stroke2_Corner0_Rounded} from '../icons/Plus' import {PlusLarge_Stroke2_Corner0_Rounded} from '../icons/Plus'
@@ -153,6 +154,7 @@ function StarterPackList({
data, data,
refetch, refetch,
isError, isError,
isLoading,
hasNextPage, hasNextPage,
isFetchingNextPage, isFetchingNextPage,
fetchNextPage, fetchNextPage,
@@ -209,6 +211,14 @@ function StarterPackList({
[_, onStartWizard], [_, onStartWizard],
) )
if (isLoading) {
return (
<View style={[a.align_center, a.p_xl]}>
<Loader size="xl" />
</View>
)
}
return ( return (
<List <List
data={membershipItems} data={membershipItems}
@@ -242,41 +252,53 @@ function StarterPackItem({
const starterPack = starterPackWithMembership.starterPack const starterPack = starterPackWithMembership.starterPack
const isInPack = !!starterPackWithMembership.listItem const isInPack = !!starterPackWithMembership.listItem
const {mutate: addMembership, isPending: isAddingPending} = const [isPendingRefresh, setIsPendingRefresh] = React.useState(false)
useListMembershipAddMutation({
onSuccess: () => { const {mutate: addMembership} = useListMembershipAddMutation({
Toast.show(_(msg`Added to starter pack`)) 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({ invalidateActorStarterPacksWithMembershipQuery({
queryClient, queryClient,
did: targetDid, did: targetDid,
}) })
}, setIsPendingRefresh(false)
onError: () => { }, 1e3)
Toast.show(_(msg`Failed to add to starter pack`), 'xmark') },
}, onError: () => {
}) Toast.show(_(msg`Failed to add to starter pack`), 'xmark')
setIsPendingRefresh(false)
},
})
const {mutate: removeMembership, isPending: isRemovingPending} = const {mutate: removeMembership} = useListMembershipRemoveMutation({
useListMembershipRemoveMutation({ onSuccess: () => {
onSuccess: () => { Toast.show(_(msg`Removed from starter pack`))
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({ invalidateActorStarterPacksWithMembershipQuery({
queryClient, queryClient,
did: targetDid, did: targetDid,
}) })
}, setIsPendingRefresh(false)
onError: () => { }, 1e3)
Toast.show(_(msg`Failed to remove from starter pack`), 'xmark') },
}, onError: () => {
}) Toast.show(_(msg`Failed to remove from starter pack`), 'xmark')
setIsPendingRefresh(false)
const isMutating = isAddingPending || isRemovingPending },
})
const handleToggleMembership = () => { const handleToggleMembership = () => {
if (!starterPack.list?.uri || isMutating) return if (!starterPack.list?.uri || isPendingRefresh) return
const listUri = starterPack.list.uri const listUri = starterPack.list.uri
setIsPendingRefresh(true)
if (!isInPack) { if (!isInPack) {
addMembership({ addMembership({
listUri: listUri, listUri: listUri,
@@ -285,6 +307,7 @@ function StarterPackItem({
} else { } else {
if (!starterPackWithMembership.listItem?.uri) { if (!starterPackWithMembership.listItem?.uri) {
console.error('Cannot remove: missing membership URI') console.error('Cannot remove: missing membership URI')
setIsPendingRefresh(false)
return return
} }
removeMembership({ removeMembership({
@@ -354,7 +377,7 @@ function StarterPackItem({
label={isInPack ? _(msg`Remove`) : _(msg`Add`)} label={isInPack ? _(msg`Remove`) : _(msg`Add`)}
color={isInPack ? 'secondary' : 'primary'} color={isInPack ? 'secondary' : 'primary'}
size="tiny" size="tiny"
disabled={isMutating} disabled={isPendingRefresh}
onPress={handleToggleMembership}> onPress={handleToggleMembership}>
<ButtonText> <ButtonText>
{isInPack ? <Trans>Remove</Trans> : <Trans>Add</Trans>} {isInPack ? <Trans>Remove</Trans> : <Trans>Add</Trans>}
+5 -13
View File
@@ -231,12 +231,10 @@ function WizardInner({
Image.prefetch([getStarterPackOgCard(currentProfile!.did, rkey)]) Image.prefetch([getStarterPackOgCard(currentProfile!.did, rkey)])
dispatch({type: 'SetProcessing', processing: false}) dispatch({type: 'SetProcessing', processing: false})
// If launched from ProfileMenu dialog, notify the dialog and go back
if (fromDialog) { if (fromDialog) {
navigation.goBack() navigation.goBack()
onSuccess?.() onSuccess?.()
} else { } else {
// Original behavior for other entry points
navigation.replace('StarterPack', { navigation.replace('StarterPack', {
name: profile!.handle, name: profile!.handle,
rkey, rkey,
@@ -246,19 +244,13 @@ function WizardInner({
} }
const onSuccessEdit = () => { const onSuccessEdit = () => {
// If launched from ProfileMenu dialog, go back to stay on profile page if (navigation.canGoBack()) {
if (fromDialog) {
navigation.goBack() navigation.goBack()
} else { } else {
// Original behavior for other entry points navigation.replace('StarterPack', {
if (navigation.canGoBack()) { name: currentAccount!.handle,
navigation.goBack() rkey: parsed!.rkey,
} else { })
navigation.replace('StarterPack', {
name: profile!.handle,
rkey: parsed!.rkey,
})
}
} }
} }
+4 -7
View File
@@ -452,13 +452,10 @@ let ProfileMenu = ({
</Menu.Outer> </Menu.Outer>
</Menu.Root> </Menu.Root>
{currentAccount && ( <StarterPackDialog
<StarterPackDialog control={addToStarterPacksDialogControl}
control={addToStarterPacksDialogControl} targetDid={profile.did}
accountDid={currentAccount.did} />
targetDid={profile.did}
/>
)}
<ReportDialog <ReportDialog
control={reportDialogControl} control={reportDialogControl}