diff --git a/src/components/AccountManager.tsx b/src/components/AccountManager.tsx index 4e678f9..5ad2bcb 100644 --- a/src/components/AccountManager.tsx +++ b/src/components/AccountManager.tsx @@ -1,17 +1,42 @@ import { useObservableMemo } from "applesauce-react/hooks"; -import { Check, User, UserX, UserPlus } from "lucide-react"; +import { Check, User, UserX, UserPlus, Eye, Puzzle } from "lucide-react"; import { toast } from "sonner"; import accountManager from "@/services/accounts"; import { useProfile } from "@/hooks/useProfile"; import { getDisplayName } from "@/lib/nostr-utils"; import { useAppShell } from "@/components/layouts/AppShellContext"; import { Button } from "@/components/ui/button"; +import { Badge } from "@/components/ui/badge"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import Nip05 from "@/components/nostr/nip05"; import type { IAccount } from "applesauce-accounts"; import type { ISigner } from "applesauce-signers"; +function getAccountTypeBadge(account: IAccount) { + const accountType = (account.constructor as unknown as { type: string }).type; + + if (accountType === "grimoire-readonly" || accountType === "readonly") { + return ( + + + Read-only + + ); + } + + if (accountType === "extension") { + return ( + + + Extension + + ); + } + + return null; +} + function AccountCard({ account, isActive, @@ -56,7 +81,10 @@ function AccountCard({
-
{displayName}
+
+
{displayName}
+ {getAccountTypeBadge(account)} +
{profile && (
diff --git a/src/components/GlobalAuthPrompt.tsx b/src/components/GlobalAuthPrompt.tsx index 4ff2dd4..8c4d8ee 100644 --- a/src/components/GlobalAuthPrompt.tsx +++ b/src/components/GlobalAuthPrompt.tsx @@ -5,6 +5,8 @@ import { Button } from "./ui/button"; import { Checkbox } from "./ui/checkbox"; import { useRelayState } from "@/hooks/useRelayState"; import { RelayLink } from "./nostr/RelayLink"; +import { useObservableMemo } from "applesauce-react/hooks"; +import accountManager from "@/services/accounts"; interface AuthToastProps { relayUrl: string; @@ -116,11 +118,20 @@ export function GlobalAuthPrompt() { relays, } = useRelayState(); + const activeAccount = useObservableMemo(() => accountManager.active$, []); const activeToasts = useRef>(new Map()); const [authenticatingRelays, setAuthenticatingRelays] = useState>( new Set(), ); + // Check if active account is read-only + const isReadOnly = + activeAccount && + ((activeAccount.constructor as unknown as { type: string }).type === + "grimoire-readonly" || + (activeAccount.constructor as unknown as { type: string }).type === + "readonly"); + // Watch for authentication success and show toast useEffect(() => { authenticatingRelays.forEach((relayUrl) => { @@ -139,6 +150,15 @@ export function GlobalAuthPrompt() { }, [relays, authenticatingRelays]); useEffect(() => { + // Don't show auth prompts if active account is read-only + if (isReadOnly) { + // Auto-reject all pending challenges for read-only accounts + pendingChallenges.forEach((challenge) => { + rejectAuth(challenge.relayUrl, true); + }); + return; + } + // Show toasts for new challenges pendingChallenges.forEach((challenge) => { const key = challenge.relayUrl; @@ -224,7 +244,13 @@ export function GlobalAuthPrompt() { activeToasts.current.delete(relayUrl); } }); - }, [pendingChallenges, authenticateRelay, rejectAuth, setAuthPreference]); + }, [ + pendingChallenges, + authenticateRelay, + rejectAuth, + setAuthPreference, + isReadOnly, + ]); return null; // No UI needed - toasts handle everything } diff --git a/src/components/LogoutHandler.tsx b/src/components/LogoutHandler.tsx index 35f9e23..f8ed76e 100644 --- a/src/components/LogoutHandler.tsx +++ b/src/components/LogoutHandler.tsx @@ -61,6 +61,15 @@ export default function LogoutHandler({ action, all }: LogoutHandlerProps) { return; } + // If there are other accounts, switch to the first one before removing current + const otherAccounts = allAccounts.filter( + (acc) => acc.id !== activeAccount.id, + ); + if (otherAccounts.length > 0) { + accountManager.setActive(otherAccounts[0].id); + } + + // Remove the account accountManager.removeAccount(activeAccount); toast.success("Logged out", { diff --git a/src/components/nostr/user-menu.tsx b/src/components/nostr/user-menu.tsx index 09c85eb..5e6122b 100644 --- a/src/components/nostr/user-menu.tsx +++ b/src/components/nostr/user-menu.tsx @@ -1,4 +1,4 @@ -import { User, Check, UserPlus } from "lucide-react"; +import { User, Check, UserPlus, Eye, Puzzle } from "lucide-react"; import accounts from "@/services/accounts"; import { ExtensionSigner } from "applesauce-signers"; import { ExtensionAccount } from "applesauce-accounts/accounts"; @@ -8,6 +8,7 @@ import { getDisplayName } from "@/lib/nostr-utils"; import { useGrimoire } from "@/core/state"; import { useAppShell } from "@/components/layouts/AppShellContext"; import { Button } from "@/components/ui/button"; +import { Badge } from "@/components/ui/badge"; import { DropdownMenu, DropdownMenuContent, @@ -25,6 +26,30 @@ import { useState } from "react"; import type { IAccount } from "applesauce-accounts"; import type { ISigner } from "applesauce-signers"; +function getAccountTypeBadge(account: IAccount) { + const accountType = (account.constructor as unknown as { type: string }).type; + + if (accountType === "grimoire-readonly" || accountType === "readonly") { + return ( + + + Read-only + + ); + } + + if (accountType === "extension") { + return ( + + + Extension + + ); + } + + return null; +} + function UserAvatar({ pubkey }: { pubkey: string }) { const profile = useProfile(pubkey); return ( @@ -40,14 +65,21 @@ function UserAvatar({ pubkey }: { pubkey: string }) { ); } -function UserLabel({ pubkey }: { pubkey: string }) { - const profile = useProfile(pubkey); +function UserLabel({ + account, +}: { + account: IAccount; +}) { + const profile = useProfile(account.pubkey); return ( -
- {getDisplayName(pubkey, profile)} +
+
+ {getDisplayName(account.pubkey, profile)} + {getAccountTypeBadge(account)} +
{profile ? ( - + ) : null}
@@ -128,7 +160,7 @@ export default function UserMenu() { >
- +
@@ -149,7 +181,7 @@ export default function UserMenu() { >
- +
))}