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
+31 -8
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({
const {mutate: addMembership} = useListMembershipAddMutation({
onSuccess: () => { onSuccess: () => {
Toast.show(_(msg`Added to starter pack`)) 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)
}, 1e3)
}, },
onError: () => { onError: () => {
Toast.show(_(msg`Failed to add to starter pack`), 'xmark') 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)
}, 1e3)
}, },
onError: () => { onError: () => {
Toast.show(_(msg`Failed to remove from starter pack`), 'xmark') 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>}
+1 -9
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,21 +244,15 @@ function WizardInner({
} }
const onSuccessEdit = () => { const onSuccessEdit = () => {
// If launched from ProfileMenu dialog, go back to stay on profile page
if (fromDialog) {
navigation.goBack()
} else {
// Original behavior for other entry points
if (navigation.canGoBack()) { if (navigation.canGoBack()) {
navigation.goBack() navigation.goBack()
} else { } else {
navigation.replace('StarterPack', { navigation.replace('StarterPack', {
name: profile!.handle, name: currentAccount!.handle,
rkey: parsed!.rkey, rkey: parsed!.rkey,
}) })
} }
} }
}
const {mutate: createStarterPack} = useCreateStarterPackMutation({ const {mutate: createStarterPack} = useCreateStarterPackMutation({
onSuccess: onSuccessCreate, onSuccess: onSuccessCreate,
-3
View File
@@ -452,13 +452,10 @@ let ProfileMenu = ({
</Menu.Outer> </Menu.Outer>
</Menu.Root> </Menu.Root>
{currentAccount && (
<StarterPackDialog <StarterPackDialog
control={addToStarterPacksDialogControl} control={addToStarterPacksDialogControl}
accountDid={currentAccount.did}
targetDid={profile.did} targetDid={profile.did}
/> />
)}
<ReportDialog <ReportDialog
control={reportDialogControl} control={reportDialogControl}