Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 103 additions & 9 deletions src/components/common/overall-layout/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ import { api } from "@/utils/api";
import useUser from "@/hooks/useUser";
import { useUserStore } from "@/lib/zustand/user";
import useAppWallet from "@/hooks/useAppWallet";
import useMultisigWallet from "@/hooks/useMultisigWallet";

import SessionProvider from "@/components/SessionProvider";
import { getServerSession } from "next-auth";

// import MenuWallets from "@/components/common/overall-layout/menus/wallets";
import MenuWallets from "@/components/common/overall-layout/menus/wallets";
import MenuWallet from "@/components/common/overall-layout/menus/multisig-wallet";
import WalletSelector from "@/components/common/overall-layout/wallet-selector";
import {
WalletDataLoaderWrapper,
DialogReportWrapper,
Expand Down Expand Up @@ -69,6 +71,7 @@ export default function RootLayout({
const { user, isLoading } = useUser();
const router = useRouter();
const { appWallet } = useAppWallet();
const { multisigWallet } = useMultisigWallet();
const { generateNsec } = useNostrChat();

const userAddress = useUserStore((state) => state.userAddress);
Expand Down Expand Up @@ -164,6 +167,43 @@ export default function RootLayout({
const walletPageNames = walletPageRoute ? walletPageRoute.split("/") : [];
const pageIsPublic = publicRoutes.includes(router.pathname);
const isLoggedIn = !!user;
const isHomepage = router.pathname === "/";

// Keep track of the last visited wallet to show wallet menu even on other pages
const [lastVisitedWalletId, setLastVisitedWalletId] = React.useState<string | null>(null);
const [lastVisitedWalletName, setLastVisitedWalletName] = React.useState<string | null>(null);
const [lastWalletStakingEnabled, setLastWalletStakingEnabled] = React.useState<boolean | null>(null);

React.useEffect(() => {
const walletId = router.query.wallet as string | undefined;
if (walletId && isWalletPath && appWallet && multisigWallet) {
setLastVisitedWalletId(walletId);
setLastVisitedWalletName(appWallet.name);
// Check if staking is enabled for this wallet
try {
const stakingEnabled = multisigWallet.stakingEnabled();
setLastWalletStakingEnabled(stakingEnabled);
} catch (error) {
// Don't update state on error - keep the last known value
console.error("Error checking staking status:", error);
}
}
}, [router.query.wallet, isWalletPath, appWallet, multisigWallet]);

const clearWalletContext = React.useCallback(() => {
setLastVisitedWalletId(null);
setLastVisitedWalletName(null);
setLastWalletStakingEnabled(null);
}, []);

// Clear wallet context when navigating to homepage
React.useEffect(() => {
if (isHomepage && lastVisitedWalletId) {
clearWalletContext();
}
}, [isHomepage, lastVisitedWalletId, clearWalletContext]);

const showWalletMenu = isLoggedIn && (isWalletPath || !!lastVisitedWalletId);

return (
<div className="flex h-screen w-screen flex-col overflow-hidden">
Expand All @@ -175,11 +215,21 @@ export default function RootLayout({
data-header="main"
>
<div className="flex h-14 items-center gap-4 lg:h-16">
{/* Mobile menu button - only in wallet context */}
{isWalletPath && <MobileNavigation isWalletPath={isWalletPath} />}
{/* Mobile menu button - hidden only on public homepage (not logged in) */}
{(isLoggedIn || !isHomepage) && (
<MobileNavigation
showWalletMenu={showWalletMenu}
isLoggedIn={isLoggedIn}
walletId={router.query.wallet as string || lastVisitedWalletId || undefined}
fallbackWalletName={lastVisitedWalletName}
onClearWallet={clearWalletContext}
stakingEnabled={lastWalletStakingEnabled ?? undefined}
isWalletPath={isWalletPath}
/>
)}

{/* Logo - in fixed-width container matching sidebar width */}
<div className={`flex items-center md:w-[260px] lg:w-[280px] ${isWalletPath ? 'flex-1 justify-center md:flex-none md:justify-start' : ''}`}>
<div className={`flex items-center md:w-[260px] lg:w-[280px] ${(isLoggedIn || !isHomepage) ? 'flex-1 justify-center md:flex-none md:justify-start' : ''}`}>
<Link
href="/"
className="flex items-center gap-2 rounded-md px-4 py-2 text-sm transition-all duration-200 hover:bg-gray-100/50 dark:hover:bg-white/5 md:px-4"
Expand Down Expand Up @@ -218,13 +268,57 @@ export default function RootLayout({
</header>

{/* Content area with sidebar + main */}
<div className={`flex flex-1 overflow-hidden ${isWalletPath ? '' : ''}`}>
{/* Sidebar for larger screens - only in wallet context */}
{isWalletPath && (
<div className={`flex flex-1 overflow-hidden`}>
{/* Sidebar for larger screens - hidden only on public homepage (not logged in) */}
{(isLoggedIn || !isHomepage) && (
<aside className="hidden w-[260px] border-r border-gray-300/50 bg-muted/40 dark:border-white/[0.03] md:block lg:w-[280px]">
<div className="flex h-full max-h-screen flex-col">
<nav className="flex-1 pt-2">
<MenuWallet />
<nav className="flex-1 pt-2 overflow-y-auto">
<div className="flex flex-col">
{/* 1. Home Link - only when NOT logged in */}
{!isLoggedIn && (
<div className="px-2 lg:px-4">
<div className="space-y-1">
<Link
href="/"
className={`flex w-full items-center gap-3 rounded-md px-3 py-2 text-sm transition-all duration-200 hover:bg-gray-100/50 dark:hover:bg-white/5 ${
router.pathname === "/"
? "text-white"
: "text-muted-foreground hover:text-foreground"
}`}
>
<svg className="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" />
</svg>
<span>Home</span>
</Link>
</div>
</div>
)}

{/* 2. Wallet Selector - only when logged in */}
{isLoggedIn && (
<WalletSelector
fallbackWalletName={lastVisitedWalletName}
onClearWallet={clearWalletContext}
/>
)}

{/* 3. Wallet Menu - shown when wallet is selected */}
{showWalletMenu && (
<div className="mt-4">
<MenuWallet
walletId={router.query.wallet as string || lastVisitedWalletId || undefined}
stakingEnabled={isWalletPath ? undefined : (lastWalletStakingEnabled ?? undefined)}
/>
</div>
)}

{/* 4. Resources Menu - always visible */}
<div className="mt-4">
<MenuWallets />
</div>
</div>
</nav>
<div className="mt-auto p-4" />
</div>
Expand Down
119 changes: 28 additions & 91 deletions src/components/common/overall-layout/menus/multisig-wallet.tsx
Original file line number Diff line number Diff line change
@@ -1,94 +1,37 @@
import { Banknote, Info, List, Landmark, UserRoundPen, ChartNoAxesColumnIncreasing, FileCode2, ArrowLeft, ChevronDown, ChevronUp, Wallet2, Plus } from "lucide-react";
import { Banknote, Info, List, Landmark, UserRoundPen, ChartNoAxesColumnIncreasing, FileCode2 } from "lucide-react";
import { useRouter } from "next/router";
import { useState, useEffect } from "react";
import MenuLink from "./menu-link";
import usePendingTransactions from "@/hooks/usePendingTransactions";
import useUserWallets from "@/hooks/useUserWallets";
import { Badge } from "@/components/ui/badge";
import { ChatBubbleIcon } from "@radix-ui/react-icons";
import usePendingSignables from "@/hooks/usePendingSignables";
import useMultisigWallet from "@/hooks/useMultisigWallet";
import useAppWallet from "@/hooks/useAppWallet";
import WalletNavLink from "@/components/common/overall-layout/wallet-nav-link";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";

export default function MenuWallet() {
interface MenuWalletProps {
walletId?: string;
stakingEnabled?: boolean;
}

export default function MenuWallet({ walletId, stakingEnabled }: MenuWalletProps) {
const router = useRouter();
const baseUrl = `/wallets/${router.query.wallet as string | undefined}/`;
const { wallets } = useUserWallets();
const { appWallet } = useAppWallet();
const effectiveWalletId = walletId || (router.query.wallet as string | undefined);
const baseUrl = `/wallets/${effectiveWalletId}/`;
const { transactions } = usePendingTransactions();
const { signables } = usePendingSignables();
const { multisigWallet } = useMultisigWallet();
const [open, setOpen] = useState(false);

// Close dropdown on route change
useEffect(() => {
const handleRouteChange = () => {
setOpen(false);
};
router.events.on("routeChangeStart", handleRouteChange);
return () => {
router.events.off("routeChangeStart", handleRouteChange);
};
}, [router.events]);

if (!wallets) return;
// Use fallback staking enabled if provided, otherwise check multisigWallet
const showStaking = stakingEnabled !== undefined
? stakingEnabled
: (multisigWallet ? multisigWallet.stakingEnabled() : false);

return (
<nav className="grid h-full items-start px-2 font-medium lg:px-4">
<div className="grid items-start px-2 font-medium lg:px-4">
<div className="grid items-start space-y-1">
{/* Wallet Selector */}
<div className="mt-1 mb-1">
<DropdownMenu open={open} onOpenChange={setOpen}>
<DropdownMenuTrigger asChild>
<button type="button" className="flex w-full max-w-[244px] lg:max-w-[248px] items-center gap-3 rounded-md px-3 py-2 text-sm transition-all duration-200 bg-white dark:bg-zinc-900 border border-zinc-300/40 dark:border-white/10 text-muted-foreground hover:bg-zinc-100 dark:hover:bg-zinc-800 hover:text-foreground">
<Wallet2 className="h-5 w-5 flex-shrink-0" />
<span className="truncate">{appWallet?.name || "Select Wallet"}</span>
{open ? (
<ChevronUp className="h-5 w-5 flex-shrink-0 ml-auto" />
) : (
<ChevronDown className="h-5 w-5 flex-shrink-0 ml-auto" />
)}
</button>
</DropdownMenuTrigger>
<DropdownMenuContent align="start" className="w-[var(--radix-dropdown-menu-trigger-width)]">
{wallets
.filter((wallet) => !wallet.isArchived)
.sort((a, b) => a.name.localeCompare(b.name))
.map((wallet) => (
<DropdownMenuItem asChild key={wallet.id}>
<WalletNavLink wallet={wallet} />
</DropdownMenuItem>
))}
<DropdownMenuSeparator />
<DropdownMenuItem asChild>
<button
type="button"
onClick={() => {
setOpen(false);
void router.push("/wallets/new-wallet-flow/save");
}}
className="flex w-full items-center gap-3 rounded-md px-3 py-2 text-sm text-muted-foreground transition-all duration-200 hover:bg-zinc-100 dark:hover:bg-zinc-800 hover:text-foreground cursor-pointer"
>
<Plus className="h-5 w-5 flex-shrink-0" />
<span>New Wallet</span>
</button>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>

{/* Menu Items */}
{/* Wallet Items */}
<div className="mt-1 pt-1 space-y-1">
<div className="px-3 py-1 text-xs font-medium text-muted-foreground">
Menu
Wallet
</div>
<MenuLink
href={`${baseUrl}`}
Expand Down Expand Up @@ -138,15 +81,17 @@ export default function MenuWallet() {
</Badge>
)}
</MenuLink>
{multisigWallet && multisigWallet.stakingEnabled() && <MenuLink
href={`${baseUrl}staking`}
className={
router.pathname == "/wallets/[wallet]/staking" ? "text-white" : ""
}
>
<ChartNoAxesColumnIncreasing className="h-5 w-5" />
Staking
</MenuLink>}
{showStaking && (
<MenuLink
href={`${baseUrl}staking`}
className={
router.pathname == "/wallets/[wallet]/staking" ? "text-white" : ""
}
>
<ChartNoAxesColumnIncreasing className="h-5 w-5" />
Staking
</MenuLink>
)}
<MenuLink
href={`${baseUrl}assets`}
className={
Expand Down Expand Up @@ -175,15 +120,7 @@ export default function MenuWallet() {
Dapps
</MenuLink>
</div>

{/* Back to All Wallets */}
<div className="mt-2 border-t border-gray-300/50 dark:border-white/[0.03] pt-1">
<MenuLink href={`/`}>
<ArrowLeft className="h-5 w-5" />
All Wallets
</MenuLink>
</div>
</div>
</nav>
</div>
);
}
Loading