diff --git a/src/components/AccountList.tsx b/src/components/AccountList.tsx index fe0daed50e..db91c26a69 100644 --- a/src/components/AccountList.tsx +++ b/src/components/AccountList.tsx @@ -7,30 +7,34 @@ import {useLingui} from '@lingui/react' import {sanitizeDisplayName} from '#/lib/strings/display-names' import {sanitizeHandle} from '#/lib/strings/handles' import {useProfilesQuery} from '#/state/queries/profile' -import {type SessionAccount, useSession} from '#/state/session' +import {type SessionAccount, useSession, useSessionApi} from '#/state/session' import {UserAvatar} from '#/view/com/util/UserAvatar' import {atoms as a, useTheme} from '#/alf' -import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check' -import {ChevronRight_Stroke2_Corner0_Rounded as Chevron} from '#/components/icons/Chevron' -import {Button} from './Button' -import {Text} from './Typography' +import {Button, ButtonText} from '#/components/Button' +import {Check_Stroke2_Corner0_Rounded as CheckIcon} from '#/components/icons/Check' +import {ChevronRight_Stroke2_Corner0_Rounded as ChevronIcon} from '#/components/icons/Chevron' +import {Text} from '#/components/Typography' +import {useDialogContext} from './Dialog' export function AccountList({ onSelectAccount, onSelectOther, otherLabel, pendingDid, + editing = false, }: { onSelectAccount: (account: SessionAccount) => void onSelectOther: () => void otherLabel?: string pendingDid: string | null + editing?: boolean }) { const {currentAccount, accounts} = useSession() const t = useTheme() const {_} = useLingui() const {data: profiles} = useProfilesQuery({ handles: accounts.map(acc => acc.did), + keepPrevious: true, }) const onPressAddAccount = useCallback(() => { @@ -46,46 +50,55 @@ export function AccountList({ {borderWidth: 1}, t.atoms.border_contrast_low, ]}> - {accounts.map(account => ( - + {accounts.map((account, i) => ( + p.did === account.did)} account={account} onSelect={onSelectAccount} isCurrentAccount={account.did === currentAccount?.did} isPendingAccount={account.did === pendingDid} + editing={editing} /> - - + ))} - + + {otherLabel ?? Other account} + + + + )} + + )} ) } @@ -96,20 +109,52 @@ function AccountItem({ onSelect, isCurrentAccount, isPendingAccount, + editing, }: { profile?: AppBskyActorDefs.ProfileViewDetailed account: SessionAccount onSelect: (account: SessionAccount) => void isCurrentAccount: boolean isPendingAccount: boolean + editing?: boolean }) { const t = useTheme() const {_} = useLingui() + const control = useDialogContext() + const {logoutCurrentAccount, removeAccount} = useSessionApi() const onPress = useCallback(() => { onSelect(account) }, [account, onSelect]) + const onPressRemove = useCallback(() => { + if (isCurrentAccount) { + control.close(() => { + logoutCurrentAccount('AccountList') + }) + } else { + removeAccount(account) + } + }, [control, logoutCurrentAccount, removeAccount, account, isCurrentAccount]) + + if (editing) { + return ( + + + + ) + } + return ( ) } + +function AccountItemContent({ + highlight, + profile, + account, + + children, +}: { + highlight?: boolean + profile?: AppBskyActorDefs.ProfileViewDetailed + account: SessionAccount + children?: React.ReactNode +}) { + const t = useTheme() + + return ( + + + + + + + {sanitizeDisplayName( + profile?.displayName || profile?.handle || account.handle, + )} + {' '} + + {sanitizeHandle(account.handle)} + + + {children} + + ) +} diff --git a/src/components/Dialog/context.ts b/src/components/Dialog/context.ts index b479bc7f06..3fb30c289d 100644 --- a/src/components/Dialog/context.ts +++ b/src/components/Dialog/context.ts @@ -9,7 +9,7 @@ import { import {BottomSheetSnapPoint} from '../../../modules/bottom-sheet/src/BottomSheet.types' export const Context = React.createContext({ - close: () => {}, + close: cb => cb?.(), isNativeDialog: false, nativeSnapPoint: BottomSheetSnapPoint.Hidden, disableDrag: false, diff --git a/src/components/dialogs/SwitchAccount.tsx b/src/components/dialogs/SwitchAccount.tsx index ea870e2da9..509b963029 100644 --- a/src/components/dialogs/SwitchAccount.tsx +++ b/src/components/dialogs/SwitchAccount.tsx @@ -1,4 +1,4 @@ -import React, {useCallback} from 'react' +import React, {useCallback, useState} from 'react' import {View} from 'react-native' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' @@ -7,9 +7,10 @@ import {useAccountSwitcher} from '#/lib/hooks/useAccountSwitcher' import {type SessionAccount, useSession} from '#/state/session' import {useLoggedOutViewControls} from '#/state/shell/logged-out' import {atoms as a} from '#/alf' +import {AccountList} from '#/components/AccountList' +import {Button, ButtonText} from '#/components/Button' import * as Dialog from '#/components/Dialog' -import {AccountList} from '../AccountList' -import {Text} from '../Typography' +import {Text} from '#/components/Typography' export function SwitchAccountDialog({ control, @@ -20,6 +21,7 @@ export function SwitchAccountDialog({ const {currentAccount} = useSession() const {onPressSwitchAccount, pendingDid} = useAccountSwitcher() const {setShowLoggedOut} = useLoggedOutViewControls() + const [editing, setEditing] = useState(false) const onSelectAccount = useCallback( (account: SessionAccount) => { @@ -44,16 +46,34 @@ export function SwitchAccountDialog({ - - - Switch Account - + + + + Switch account + + + + diff --git a/src/lib/statsig/events.ts b/src/lib/statsig/events.ts index 9a306ee4f4..024b69696e 100644 --- a/src/lib/statsig/events.ts +++ b/src/lib/statsig/events.ts @@ -13,7 +13,12 @@ export type LogEvents = { withPassword: boolean } 'account:loggedOut': { - logContext: 'SwitchAccount' | 'Settings' | 'SignupQueued' | 'Deactivated' + logContext: + | 'SwitchAccount' + | 'Settings' + | 'SignupQueued' + | 'Deactivated' + | 'AccountList' scope: 'current' | 'every' } 'notifications:openApp': {} diff --git a/src/state/queries/profile.ts b/src/state/queries/profile.ts index 3059d9efea..1726d6f677 100644 --- a/src/state/queries/profile.ts +++ b/src/state/queries/profile.ts @@ -10,6 +10,7 @@ import { ComAtprotoRepoUploadBlob, } from '@atproto/api' import { + keepPreviousData, QueryClient, useMutation, useQuery, @@ -81,7 +82,13 @@ export function useProfileQuery({ }) } -export function useProfilesQuery({handles}: {handles: string[]}) { +export function useProfilesQuery({ + handles, + keepPrevious, +}: { + handles: string[] + keepPrevious: boolean +}) { const agent = useAgent() return useQuery({ staleTime: STALE.MINUTES.FIVE, @@ -90,6 +97,7 @@ export function useProfilesQuery({handles}: {handles: string[]}) { const res = await agent.getProfiles({actors: handles}) return res.data }, + placeholderData: keepPrevious ? keepPreviousData : undefined, }) }