diff --git a/aastar-frontend/app/transfer/page.tsx b/aastar-frontend/app/transfer/page.tsx index 647bdf0..9480bb6 100644 --- a/aastar-frontend/app/transfer/page.tsx +++ b/aastar-frontend/app/transfer/page.tsx @@ -5,6 +5,7 @@ import { useRouter } from "next/navigation"; import Layout from "@/components/Layout"; import TokenSelector from "@/components/TokenSelector"; import TransferSkeleton from "@/components/TransferSkeleton"; +import NetworkSwitcher from "@/components/NetworkSwitcher"; import { useDashboard } from "@/contexts/DashboardContext"; import { transferAPI, tokenAPI, paymasterAPI, addressBookAPI } from "@/lib/api"; import { GasEstimate, Token, TokenBalance } from "@/lib/types"; @@ -875,6 +876,10 @@ export default function TransferPage() {
+ {/* Network indicator + switcher (always visible so the active chain is explicit). */} +
+ +
{/* Header - Desktop only */}
diff --git a/aastar-frontend/components/NetworkSwitcher.tsx b/aastar-frontend/components/NetworkSwitcher.tsx new file mode 100644 index 0000000..3de9af5 --- /dev/null +++ b/aastar-frontend/components/NetworkSwitcher.tsx @@ -0,0 +1,96 @@ +"use client"; + +import { useEffect, useRef, useState } from "react"; +import { CHAIN_SEPOLIA } from "@aastar/sdk/core"; +import toast from "react-hot-toast"; +import { ChevronDownIcon } from "@heroicons/react/24/outline"; + +/** + * Network indicator + switcher. Makes the active network explicit (so the app never + * silently assumes a chain) and frames the roadmap. Transfers currently run only on + * Sepolia — the full AA stack (KMS / DVT / paymaster / contracts) is Sepolia-only — so + * other networks are shown as "Coming soon" (OP mainnet is the phase-2 target) rather + * than offering a switch that would fail. Wire real switching here when mainnet lands. + */ +interface NetOption { + id: number; + name: string; + testnet?: boolean; + available: boolean; +} + +const NETWORKS: NetOption[] = [ + { id: CHAIN_SEPOLIA, name: "Sepolia", testnet: true, available: true }, + { id: 10, name: "OP Mainnet", available: false }, +]; + +export default function NetworkSwitcher({ chainId = CHAIN_SEPOLIA }: { chainId?: number }) { + const [open, setOpen] = useState(false); + const ref = useRef(null); + const current = NETWORKS.find(n => n.id === chainId) ?? NETWORKS[0]; + + useEffect(() => { + if (!open) return; + const onDown = (e: PointerEvent) => { + if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false); + }; + document.addEventListener("pointerdown", onDown); + return () => document.removeEventListener("pointerdown", onDown); + }, [open]); + + const select = (n: NetOption) => { + setOpen(false); + if (!n.available) { + toast(`${n.name} is coming soon — transfers currently run on Sepolia.`, { icon: "🛠️" }); + } + }; + + return ( +
+ + {open && ( +
+ {NETWORKS.map(n => ( + + ))} +
+ )} +
+ ); +}