From b7eef743bd10b693db91c52fdd07795c367e9a39 Mon Sep 17 00:00:00 2001 From: Sean O'Connor Date: Mon, 29 Jun 2026 22:01:41 -0400 Subject: [PATCH] Fix mobile account session selection --- app.json | 2 +- app/(auth)/index.tsx | 7 ++ app/(auth)/select-account.tsx | 159 ++++++++++++++++++++++++++++++++++ app/(auth)/sign-in.tsx | 7 +- app/_layout.tsx | 3 +- contexts/AccountsContext.tsx | 11 +-- lib/accounts.ts | 21 ++++- lib/auth-cookie.ts | 86 +++++++++++++++--- lib/auth-storage.ts | 17 +++- 9 files changed, 286 insertions(+), 27 deletions(-) create mode 100644 app/(auth)/select-account.tsx diff --git a/app.json b/app.json index a369176..e8b2faf 100644 --- a/app.json +++ b/app.json @@ -10,7 +10,7 @@ "ios": { "supportsTablet": true, "bundleIdentifier": "com.beenvoice.app", - "buildNumber": "18", + "buildNumber": "20", "icon": "./assets/beenvoice.icon", "infoPlist": { "ITSAppUsesNonExemptEncryption": false, diff --git a/app/(auth)/index.tsx b/app/(auth)/index.tsx index 395cf3e..fe31b03 100644 --- a/app/(auth)/index.tsx +++ b/app/(auth)/index.tsx @@ -1,5 +1,12 @@ import { Redirect } from "expo-router"; +import { useAccounts } from "@/contexts/AccountsContext"; export default function AuthIndex() { + const { accounts, activeAccountId } = useAccounts(); + + if (!activeAccountId && accounts.length > 0) { + return ; + } + return ; } diff --git a/app/(auth)/select-account.tsx b/app/(auth)/select-account.tsx new file mode 100644 index 0000000..9cf8e51 --- /dev/null +++ b/app/(auth)/select-account.tsx @@ -0,0 +1,159 @@ +import { Ionicons } from "@expo/vector-icons"; +import { Redirect, router } from "expo-router"; +import { useState } from "react"; +import { ActivityIndicator, Pressable, StyleSheet, Text, View } from "react-native"; + +import { AuthCard } from "@/components/auth/AuthCard"; +import { AuthCardHeader } from "@/components/auth/AuthCardHeader"; +import { AuthScreenLayout } from "@/components/auth/AuthScreenLayout"; +import { Button } from "@/components/ui/Button"; +import { fonts, radii, spacing } from "@/constants/theme"; +import { useAccounts } from "@/contexts/AccountsContext"; +import { useAppTheme } from "@/contexts/ThemeContext"; +import { startAdditionalAccountSignIn } from "@/lib/add-account"; +import { formatServerHost } from "@/lib/server-mode"; + +function initials(name: string, email: string) { + const source = name.trim() || email.trim(); + const parts = source.split(/\s+/).filter(Boolean); + if (parts.length >= 2) { + return `${parts[0]![0] ?? ""}${parts[1]![0] ?? ""}`.toUpperCase(); + } + return (source[0] ?? "?").toUpperCase(); +} + +export default function SelectAccountScreen() { + const { colors } = useAppTheme(); + const { accounts, activeAccountId, switchAccount, clearActiveAccount } = useAccounts(); + const [selectingId, setSelectingId] = useState(null); + const [adding, setAdding] = useState(false); + + async function handleSelect(accountId: string) { + if (selectingId) return; + setSelectingId(accountId); + try { + await switchAccount(accountId); + router.replace("/(auth)/sign-in"); + } finally { + setSelectingId(null); + } + } + + async function handleAddAccount() { + if (adding) return; + setAdding(true); + try { + await startAdditionalAccountSignIn(clearActiveAccount); + } finally { + setAdding(false); + } + } + + if (activeAccountId || accounts.length === 0) { + return ; + } + + return ( + + + + + + {accounts.map((account) => { + const isSelecting = selectingId === account.id; + + return ( + void handleSelect(account.id)} + style={({ pressed }) => [ + styles.accountRow, + { backgroundColor: colors.muted, borderColor: colors.border }, + pressed && styles.pressed, + ]} + > + + + {initials(account.name, account.email)} + + + + + {account.name || account.email} + + + {account.email} + + + {formatServerHost(account.instanceUrl)} + + + {isSelecting ? ( + + ) : ( + + )} + + ); + })} + + +