about summary refs log tree commit diff
path: root/src/view/screens/Settings.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/screens/Settings.tsx')
-rw-r--r--src/view/screens/Settings.tsx233
1 files changed, 138 insertions, 95 deletions
diff --git a/src/view/screens/Settings.tsx b/src/view/screens/Settings.tsx
index 062533c27..e56a50d79 100644
--- a/src/view/screens/Settings.tsx
+++ b/src/view/screens/Settings.tsx
@@ -57,7 +57,8 @@ import {
   useRequireAltTextEnabled,
   useSetRequireAltTextEnabled,
 } from '#/state/preferences'
-import {useSession, useSessionApi} from '#/state/session'
+import {useSession, useSessionApi, SessionAccount} from '#/state/session'
+import {useProfileQuery} from '#/state/queries/profile'
 
 // TEMPORARY (APP-700)
 // remove after backend testing finishes
@@ -67,6 +68,70 @@ import {STATUS_PAGE_URL} from 'lib/constants'
 import {Trans, msg} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 
+function SettingsAccountCard({account}: {account: SessionAccount}) {
+  const pal = usePalette('default')
+  const {isSwitchingAccounts, currentAccount} = useSession()
+  const {logout} = useSessionApi()
+  const {data: profile} = useProfileQuery({did: account.did})
+  const isCurrentAccount = account.did === currentAccount?.did
+  const {onPressSwitchAccount} = useAccountSwitcher()
+
+  const contents = (
+    <View style={[pal.view, styles.linkCard]}>
+      <View style={styles.avi}>
+        <UserAvatar size={40} avatar={profile?.avatar} />
+      </View>
+      <View style={[s.flex1]}>
+        <Text type="md-bold" style={pal.text}>
+          {profile?.displayName || account.handle}
+        </Text>
+        <Text type="sm" style={pal.textLight}>
+          {account.handle}
+        </Text>
+      </View>
+
+      {isCurrentAccount ? (
+        <TouchableOpacity
+          testID="signOutBtn"
+          onPress={logout}
+          accessibilityRole="button"
+          accessibilityLabel="Sign out"
+          accessibilityHint={`Signs ${profile?.displayName} out of Bluesky`}>
+          <Text type="lg" style={pal.link}>
+            Sign out
+          </Text>
+        </TouchableOpacity>
+      ) : (
+        <AccountDropdownBtn account={account} />
+      )}
+    </View>
+  )
+
+  return isCurrentAccount ? (
+    <Link
+      href={makeProfileLink({
+        did: currentAccount?.did,
+        handle: currentAccount?.handle,
+      })}
+      title="Your profile"
+      noFeedback>
+      {contents}
+    </Link>
+  ) : (
+    <TouchableOpacity
+      testID={`switchToAccountBtn-${account.handle}`}
+      key={account.did}
+      onPress={
+        isSwitchingAccounts ? undefined : () => onPressSwitchAccount(account)
+      }
+      accessibilityRole="button"
+      accessibilityLabel={`Switch to ${account.handle}`}
+      accessibilityHint="Switches the account you are logged in to">
+      {contents}
+    </TouchableOpacity>
+  )
+}
+
 type Props = NativeStackScreenProps<CommonNavigatorParams, 'Settings'>
 export const SettingsScreen = withAuthRequired(
   observer(function Settings({}: Props) {
@@ -82,14 +147,12 @@ export const SettingsScreen = withAuthRequired(
     const navigation = useNavigation<NavigationProp>()
     const {isMobile} = useWebMediaQueries()
     const {screen, track} = useAnalytics()
-    const [isSwitching, setIsSwitching, onPressSwitchAccount] =
-      useAccountSwitcher()
     const [debugHeaderEnabled, toggleDebugHeader] = useDebugHeaderSetting(
       store.agent,
     )
     const {openModal} = useModalControls()
-    const {logout} = useSessionApi()
-    const {accounts} = useSession()
+    const {isSwitchingAccounts, accounts, currentAccount} = useSession()
+    const {clearCurrentAccount} = useSessionApi()
 
     const primaryBg = useCustomPalette<ViewStyle>({
       light: {backgroundColor: colors.blue0},
@@ -120,30 +183,27 @@ export const SettingsScreen = withAuthRequired(
       track('Settings:AddAccountButtonClicked')
       navigation.navigate('HomeTab')
       navigation.dispatch(StackActions.popToTop())
-      store.session.clear()
-    }, [track, navigation, store])
+      clearCurrentAccount()
+    }, [track, navigation, clearCurrentAccount])
 
     const onPressChangeHandle = React.useCallback(() => {
       track('Settings:ChangeHandleButtonClicked')
       openModal({
         name: 'change-handle',
         onChanged() {
-          setIsSwitching(true)
           store.session.reloadFromServer().then(
             () => {
-              setIsSwitching(false)
               Toast.show('Your handle has been updated')
             },
             err => {
               logger.error('Failed to reload from server after handle update', {
                 error: err,
               })
-              setIsSwitching(false)
             },
           )
         },
       })
-    }, [track, store, openModal, setIsSwitching])
+    }, [track, store, openModal])
 
     const onPressInviteCodes = React.useCallback(() => {
       track('Settings:InvitecodesButtonClicked')
@@ -154,12 +214,6 @@ export const SettingsScreen = withAuthRequired(
       navigation.navigate('LanguageSettings')
     }, [navigation])
 
-    const onPressSignout = React.useCallback(() => {
-      track('Settings:SignOutButtonClicked')
-      logout()
-      store.session.logout()
-    }, [track, store, logout])
-
     const onPressDeleteAccount = React.useCallback(() => {
       openModal({name: 'delete-account'})
     }, [openModal])
@@ -217,7 +271,7 @@ export const SettingsScreen = withAuthRequired(
           contentContainerStyle={isMobile && pal.viewLight}
           scrollIndicatorInsets={{right: 1}}>
           <View style={styles.spacer20} />
-          {store.session.currentSession !== undefined ? (
+          {currentAccount ? (
             <>
               <Text type="xl-bold" style={[pal.text, styles.heading]}>
                 <Trans>Account</Trans>
@@ -226,7 +280,7 @@ export const SettingsScreen = withAuthRequired(
                 <Text type="lg-medium" style={pal.text}>
                   Email:{' '}
                 </Text>
-                {!store.session.emailNeedsConfirmation && (
+                {currentAccount.emailConfirmed && (
                   <>
                     <FontAwesomeIcon
                       icon="check"
@@ -236,7 +290,7 @@ export const SettingsScreen = withAuthRequired(
                   </>
                 )}
                 <Text type="lg" style={pal.text}>
-                  {store.session.currentSession?.email}{' '}
+                  {currentAccount.email}{' '}
                 </Text>
                 <Link onPress={() => openModal({name: 'change-email'})}>
                   <Text type="lg" style={pal.link}>
@@ -255,7 +309,8 @@ export const SettingsScreen = withAuthRequired(
                 </Link>
               </View>
               <View style={styles.spacer20} />
-              <EmailConfirmationNotice />
+
+              {!currentAccount.emailConfirmed && <EmailConfirmationNotice />}
             </>
           ) : null}
           <View style={[s.flexRow, styles.heading]}>
@@ -264,70 +319,29 @@ export const SettingsScreen = withAuthRequired(
             </Text>
             <View style={s.flex1} />
           </View>
-          {isSwitching ? (
+
+          {isSwitchingAccounts ? (
             <View style={[pal.view, styles.linkCard]}>
               <ActivityIndicator />
             </View>
           ) : (
-            <Link
-              href={makeProfileLink(store.me)}
-              title="Your profile"
-              noFeedback>
-              <View style={[pal.view, styles.linkCard]}>
-                <View style={styles.avi}>
-                  <UserAvatar size={40} avatar={store.me.avatar} />
-                </View>
-                <View style={[s.flex1]}>
-                  <Text type="md-bold" style={pal.text} numberOfLines={1}>
-                    {store.me.displayName || store.me.handle}
-                  </Text>
-                  <Text type="sm" style={pal.textLight} numberOfLines={1}>
-                    {store.me.handle}
-                  </Text>
-                </View>
-                <TouchableOpacity
-                  testID="signOutBtn"
-                  onPress={isSwitching ? undefined : onPressSignout}
-                  accessibilityRole="button"
-                  accessibilityLabel={_(msg`Sign out`)}
-                  accessibilityHint={`Signs ${store.me.displayName} out of Bluesky`}>
-                  <Text type="lg" style={pal.link}>
-                    <Trans>Sign out</Trans>
-                  </Text>
-                </TouchableOpacity>
-              </View>
-            </Link>
+            <SettingsAccountCard account={currentAccount!} />
           )}
-          {accounts.map(account => (
-            <TouchableOpacity
-              testID={`switchToAccountBtn-${account.handle}`}
-              key={account.did}
-              style={[pal.view, styles.linkCard, isSwitching && styles.dimmed]}
-              onPress={
-                isSwitching ? undefined : () => onPressSwitchAccount(account)
-              }
-              accessibilityRole="button"
-              accessibilityLabel={`Switch to ${account.handle}`}
-              accessibilityHint="Switches the account you are logged in to">
-              <View style={styles.avi}>
-                {/*<UserAvatar size={40} avatar={account.aviUrl} />*/}
-              </View>
-              <View style={[s.flex1]}>
-                <Text type="md-bold" style={pal.text}>
-                  {/* @ts-ignore */}
-                  {account.displayName || account.handle}
-                </Text>
-                <Text type="sm" style={pal.textLight}>
-                  {account.handle}
-                </Text>
-              </View>
-              <AccountDropdownBtn handle={account.handle} />
-            </TouchableOpacity>
-          ))}
+
+          {accounts
+            .filter(a => a.did !== currentAccount?.did)
+            .map(account => (
+              <SettingsAccountCard key={account.did} account={account} />
+            ))}
+
           <TouchableOpacity
             testID="switchToNewAccountBtn"
-            style={[styles.linkCard, pal.view, isSwitching && styles.dimmed]}
-            onPress={isSwitching ? undefined : onPressAddAccount}
+            style={[
+              styles.linkCard,
+              pal.view,
+              isSwitchingAccounts && styles.dimmed,
+            ]}
+            onPress={isSwitchingAccounts ? undefined : onPressAddAccount}
             accessibilityRole="button"
             accessibilityLabel={_(msg`Add account`)}
             accessibilityHint="Create a new Bluesky account">
@@ -349,8 +363,12 @@ export const SettingsScreen = withAuthRequired(
           </Text>
           <TouchableOpacity
             testID="inviteFriendBtn"
-            style={[styles.linkCard, pal.view, isSwitching && styles.dimmed]}
-            onPress={isSwitching ? undefined : onPressInviteCodes}
+            style={[
+              styles.linkCard,
+              pal.view,
+              isSwitchingAccounts && styles.dimmed,
+            ]}
+            onPress={isSwitchingAccounts ? undefined : onPressInviteCodes}
             accessibilityRole="button"
             accessibilityLabel={_(msg`Invite`)}
             accessibilityHint="Opens invite code list">
@@ -427,7 +445,11 @@ export const SettingsScreen = withAuthRequired(
           </Text>
           <TouchableOpacity
             testID="preferencesHomeFeedButton"
-            style={[styles.linkCard, pal.view, isSwitching && styles.dimmed]}
+            style={[
+              styles.linkCard,
+              pal.view,
+              isSwitchingAccounts && styles.dimmed,
+            ]}
             onPress={openHomeFeedPreferences}
             accessibilityRole="button"
             accessibilityHint=""
@@ -444,7 +466,11 @@ export const SettingsScreen = withAuthRequired(
           </TouchableOpacity>
           <TouchableOpacity
             testID="preferencesThreadsButton"
-            style={[styles.linkCard, pal.view, isSwitching && styles.dimmed]}
+            style={[
+              styles.linkCard,
+              pal.view,
+              isSwitchingAccounts && styles.dimmed,
+            ]}
             onPress={openThreadsPreferences}
             accessibilityRole="button"
             accessibilityHint=""
@@ -462,7 +488,11 @@ export const SettingsScreen = withAuthRequired(
           </TouchableOpacity>
           <TouchableOpacity
             testID="savedFeedsBtn"
-            style={[styles.linkCard, pal.view, isSwitching && styles.dimmed]}
+            style={[
+              styles.linkCard,
+              pal.view,
+              isSwitchingAccounts && styles.dimmed,
+            ]}
             accessibilityHint="My Saved Feeds"
             accessibilityLabel={_(msg`Opens screen with all saved feeds`)}
             onPress={onPressSavedFeeds}>
@@ -475,8 +505,12 @@ export const SettingsScreen = withAuthRequired(
           </TouchableOpacity>
           <TouchableOpacity
             testID="languageSettingsBtn"
-            style={[styles.linkCard, pal.view, isSwitching && styles.dimmed]}
-            onPress={isSwitching ? undefined : onPressLanguageSettings}
+            style={[
+              styles.linkCard,
+              pal.view,
+              isSwitchingAccounts && styles.dimmed,
+            ]}
+            onPress={isSwitchingAccounts ? undefined : onPressLanguageSettings}
             accessibilityRole="button"
             accessibilityHint="Language settings"
             accessibilityLabel={_(msg`Opens configurable language settings`)}>
@@ -492,9 +526,15 @@ export const SettingsScreen = withAuthRequired(
           </TouchableOpacity>
           <TouchableOpacity
             testID="moderationBtn"
-            style={[styles.linkCard, pal.view, isSwitching && styles.dimmed]}
+            style={[
+              styles.linkCard,
+              pal.view,
+              isSwitchingAccounts && styles.dimmed,
+            ]}
             onPress={
-              isSwitching ? undefined : () => navigation.navigate('Moderation')
+              isSwitchingAccounts
+                ? undefined
+                : () => navigation.navigate('Moderation')
             }
             accessibilityRole="button"
             accessibilityHint=""
@@ -513,7 +553,11 @@ export const SettingsScreen = withAuthRequired(
           </Text>
           <TouchableOpacity
             testID="appPasswordBtn"
-            style={[styles.linkCard, pal.view, isSwitching && styles.dimmed]}
+            style={[
+              styles.linkCard,
+              pal.view,
+              isSwitchingAccounts && styles.dimmed,
+            ]}
             onPress={onPressAppPasswords}
             accessibilityRole="button"
             accessibilityHint="Open app password settings"
@@ -530,8 +574,12 @@ export const SettingsScreen = withAuthRequired(
           </TouchableOpacity>
           <TouchableOpacity
             testID="changeHandleBtn"
-            style={[styles.linkCard, pal.view, isSwitching && styles.dimmed]}
-            onPress={isSwitching ? undefined : onPressChangeHandle}
+            style={[
+              styles.linkCard,
+              pal.view,
+              isSwitchingAccounts && styles.dimmed,
+            ]}
+            onPress={isSwitchingAccounts ? undefined : onPressChangeHandle}
             accessibilityRole="button"
             accessibilityLabel={_(msg`Change handle`)}
             accessibilityHint="Choose a new Bluesky username or create">
@@ -655,15 +703,10 @@ const EmailConfirmationNotice = observer(
   function EmailConfirmationNoticeImpl() {
     const pal = usePalette('default')
     const palInverted = usePalette('inverted')
-    const store = useStores()
     const {_} = useLingui()
     const {isMobile} = useWebMediaQueries()
     const {openModal} = useModalControls()
 
-    if (!store.session.emailNeedsConfirmation) {
-      return null
-    }
-
     return (
       <View style={{marginBottom: 20}}>
         <Text type="xl-bold" style={[pal.text, styles.heading]}>