diff --git a/src/components/common/cardano-objects/connect-wallet.tsx b/src/components/common/cardano-objects/connect-wallet.tsx index 456d8752..be8c98dc 100644 --- a/src/components/common/cardano-objects/connect-wallet.tsx +++ b/src/components/common/cardano-objects/connect-wallet.tsx @@ -1,4 +1,4 @@ -import { Wallet, Loader2, CheckCircle2, AlertCircle } from "lucide-react"; +import { Wallet, Loader2, CheckCircle2, AlertCircle, ShieldCheck } from "lucide-react"; import { Button } from "@/components/ui/button"; import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"; import { @@ -98,6 +98,7 @@ function ConnectWalletContent({ const { user, isLoading: isUserLoading } = useUser(); const userAddress = useUserStore((state) => state.userAddress); const setUserAddress = useUserStore((state) => state.setUserAddress); + const requestReauth = useUserStore((state) => state.requestReauth); const { toast } = useToast(); // Use WalletContext for regular wallet connection @@ -654,6 +655,17 @@ function ConnectWalletContent({ ); } + // Connected but the user query resolved with no user → no wallet session + // was established (authorization failed/cancelled). Don't spin forever: + // show an actionable "Authorize" label; the dropdown offers re-authorize. + if (isConnected && !user && !isUserLoading && !isConnecting) { + return ( + <> + + Authorize + + ); + } if (isConnected && isLoading) { return ( <> @@ -745,6 +757,22 @@ function ConnectWalletContent({ {isConnected && ( <> + {!user && !isUserLoading && ( + requestReauth()} + className={cn( + "px-3 py-2.5 rounded-md", + "text-zinc-900 dark:text-zinc-50", + "hover:bg-zinc-100 dark:hover:bg-zinc-800", + "focus:bg-zinc-100 dark:focus:bg-zinc-800", + "transition-colors duration-150", + "cursor-pointer" + )} + > + + Authorize wallet + + )} state.userAddress); const setUserAddress = useUserStore((state) => state.setUserAddress); + const reauthNonce = useUserStore((state) => state.reauthNonce); const ctx = api.useUtils(); // State for wallet authorization modal @@ -257,7 +263,7 @@ export default function RootLayout({ activeWallet.getUsedAddresses() .then((addresses) => { if (addresses && addresses.length > 0) { - setUserAddress(addresses[0]!); + setUserAddress(normalizeAddressToBech32(addresses[0]!)); fetchingAddressRef.current = false; } else { return activeWallet.getUnusedAddresses(); @@ -265,7 +271,7 @@ export default function RootLayout({ }) .then((addresses) => { if (addresses && addresses.length > 0 && !userAddress) { - setUserAddress(addresses[0]!); + setUserAddress(normalizeAddressToBech32(addresses[0]!)); } fetchingAddressRef.current = false; }) @@ -398,6 +404,21 @@ export default function RootLayout({ // Don't refetch here - let the natural query refetch handle it if needed }, []); + // Manual re-authorization: when the user is connected but never got a + // session (e.g. the auto-authorize failed/was cancelled), hasCheckedSession + // stays true and the modal never reopens — leaving the connect button stuck + // on "Loading…". Bumping reauthNonce (from the connect dropdown) clears that + // latch and refetches the session so the session-check effect reopens the + // auth modal. + useEffect(() => { + if (reauthNonce > 0) { + setHasCheckedSession(false); + setCheckingSession(false); + setShowAuthModal(false); + void refetchWalletSession(); + } + }, [reauthNonce, refetchWalletSession]); + const handleAuthModalAuthorized = useCallback(async () => { setShowAuthModal(false); setCheckingSession(false); diff --git a/src/lib/zustand/user.ts b/src/lib/zustand/user.ts index 076383cb..aadfe0ac 100644 --- a/src/lib/zustand/user.ts +++ b/src/lib/zustand/user.ts @@ -25,6 +25,11 @@ interface UserState { setPastWallet: (pastWallet: string | undefined) => void; pastUtxosEnabled: boolean; setPastUtxosEnabled: (enabled: boolean | ((prev: boolean) => boolean)) => void; + // Bumped when the user explicitly asks to re-run wallet authorization + // (e.g. after a failed/cancelled auto-authorize left them connected but + // unauthorized). The layout watches this to reopen the auth modal. + reauthNonce: number; + requestReauth: () => void; } export const useUserStore = create()( @@ -36,6 +41,8 @@ export const useUserStore = create()( setUser: (user) => set({ user }), pastWallet: undefined, setPastWallet: (wallet) => set({ pastWallet: wallet }), + reauthNonce: 0, + requestReauth: () => set((state) => ({ reauthNonce: state.reauthNonce + 1 })), pastUtxosEnabled: false, setPastUtxosEnabled: (enabled) => { const newValue = typeof enabled === "function" ? enabled(get().pastUtxosEnabled) : enabled;