added network select feature

This commit is contained in:
Siavash Sameni
2025-08-28 15:16:02 +04:00
parent f60e4ca3a5
commit 62653437b5
4 changed files with 93 additions and 22 deletions

View File

@@ -36,6 +36,10 @@ const defaultSettings: NotificationSettings = {
export default function SettingsModal({ open, initial, onClose, onSave }: SettingsModalProps) {
const [form, setForm] = useState<NotificationSettings>(initial || defaultSettings);
const [testStatus, setTestStatus] = useState<string>("");
// RPC runtime overrides (stored in localStorage)
const [rpcBase, setRpcBase] = useState<string>("");
const [rpcArbitrum, setRpcArbitrum] = useState<string>("");
const [rpcMainnet, setRpcMainnet] = useState<string>("");
useEffect(() => {
if (open) {
@@ -45,6 +49,16 @@ export default function SettingsModal({ open, initial, onClose, onSave }: Settin
if (!merged.ntfyServer) merged.ntfyServer = ENV_NTFY;
if (!merged.schedyBaseUrl) merged.schedyBaseUrl = ENV_SCHEDY;
setForm(merged);
// Load RPC overrides from localStorage
try {
const ls = typeof window !== 'undefined' ? window.localStorage : undefined;
const b = ls?.getItem('rpc:base') || '';
const a = ls?.getItem('rpc:arbitrum') || '';
const m = ls?.getItem('rpc:mainnet') || '';
setRpcBase(b || 'https://base.llamarpc.com');
setRpcArbitrum(a || '');
setRpcMainnet(m || '');
} catch {}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [open, initial]);
@@ -284,6 +298,41 @@ export default function SettingsModal({ open, initial, onClose, onSave }: Settin
</div>
</>
)}
{/* RPC settings */}
<div className="col-span-2 mt-2 border-t border-gray-700 pt-2">
<div className="text-sm font-semibold text-gray-200 mb-1">RPC endpoints (per network)</div>
<div className="grid grid-cols-2 gap-3">
<label>
<span className="text-gray-300">Base RPC (default https://base.llamarpc.com)</span>
<input
className="mt-1 w-full rounded border border-gray-700 bg-gray-800 px-2 py-1 text-gray-100"
placeholder="https://base.llamarpc.com"
value={rpcBase}
onChange={(e) => setRpcBase(e.target.value)}
/>
</label>
<label>
<span className="text-gray-300">Arbitrum RPC (optional)</span>
<input
className="mt-1 w-full rounded border border-gray-700 bg-gray-800 px-2 py-1 text-gray-100"
placeholder="https://arb.yourrpc.example"
value={rpcArbitrum}
onChange={(e) => setRpcArbitrum(e.target.value)}
/>
</label>
<label className="col-span-2">
<span className="text-gray-300">Mainnet RPC (optional)</span>
<input
className="mt-1 w-full rounded border border-gray-700 bg-gray-800 px-2 py-1 text-gray-100"
placeholder="https://mainnet.yourrpc.example"
value={rpcMainnet}
onChange={(e) => setRpcMainnet(e.target.value)}
/>
</label>
<div className="col-span-2 text-xs text-gray-400">Changes apply immediately after Save without rebuild.</div>
</div>
</div>
</div>
<div className="mt-4 flex justify-end gap-2">
@@ -307,7 +356,27 @@ export default function SettingsModal({ open, initial, onClose, onSave }: Settin
<button
className="rounded bg-indigo-600 px-3 py-1.5 disabled:opacity-50"
disabled={saveDisabled}
onClick={() => onSave(form)}
onClick={() => {
// Persist RPC overrides
try {
if (typeof window !== 'undefined' && window.localStorage) {
const ls = window.localStorage;
const b = (rpcBase || '').trim();
const a = (rpcArbitrum || '').trim();
const m = (rpcMainnet || '').trim();
if (b) ls.setItem('rpc:base', b); else ls.removeItem('rpc:base');
if (a) ls.setItem('rpc:arbitrum', a); else ls.removeItem('rpc:arbitrum');
if (m) ls.setItem('rpc:mainnet', m); else ls.removeItem('rpc:mainnet');
}
} catch {}
onSave(form);
try {
if (typeof window !== 'undefined') {
// Ensure new RPCs are applied by reloading the app
setTimeout(() => window.location.reload(), 150);
}
} catch {}
}}
>
Save
</button>

View File

@@ -10,16 +10,32 @@ const metadata = {
};
// Prefer custom RPCs to avoid public-provider rate limits (429)
const baseRpc = process.env.NEXT_PUBLIC_RPC_BASE;
const arbitrumRpc = process.env.NEXT_PUBLIC_RPC_ARBITRUM;
// Support runtime overrides via localStorage:
// - rpc:base
// - rpc:arbitrum
// - rpc:mainnet
function runtimeRpc(key: string): string | null {
try {
if (typeof window !== 'undefined' && window.localStorage) {
const v = window.localStorage.getItem(key);
return (v && v.trim()) ? v.trim() : null;
}
} catch {}
return null;
}
const enableMainnet = process.env.NEXT_PUBLIC_ENABLE_MAINNET === 'true';
const baseRpc = runtimeRpc('rpc:base') || process.env.NEXT_PUBLIC_RPC_BASE || 'https://base.llamarpc.com';
const arbitrumRpc = runtimeRpc('rpc:arbitrum') || process.env.NEXT_PUBLIC_RPC_ARBITRUM || '';
const mainnetRpc = runtimeRpc('rpc:mainnet') || '';
export const config = createConfig({
chains: [base, arbitrum, ...(enableMainnet ? [mainnet] : []), sepolia],
transports: {
[base.id]: baseRpc ? http(baseRpc, { batch: true, retryCount: 2, retryDelay: 250 }) : http(undefined, { batch: true, retryCount: 2, retryDelay: 250 }),
[arbitrum.id]: arbitrumRpc ? http(arbitrumRpc, { batch: true, retryCount: 2, retryDelay: 250 }) : http(undefined, { batch: true, retryCount: 2, retryDelay: 250 }),
[mainnet.id]: http(),
[mainnet.id]: mainnetRpc ? http(mainnetRpc, { batch: true, retryCount: 2, retryDelay: 250 }) : http(),
[sepolia.id]: http(),
},
ssr: true,

View File

@@ -1,9 +1,9 @@
'use client';
import { WagmiProvider, createConfig, http } from 'wagmi';
import { mainnet, sepolia, base, arbitrum } from 'wagmi/chains';
import { WagmiProvider } from 'wagmi';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { PropsWithChildren, useEffect, useState } from 'react';
import { config } from '../config/web3';
const metadata = {
name: 'MortgageFi',
@@ -12,21 +12,6 @@ const metadata = {
icons: ['https://mortgagefi.app/logo.png']
};
// Prefer custom RPCs to avoid public-provider rate limits (429)
const baseRpc = process.env.NEXT_PUBLIC_RPC_BASE;
const arbitrumRpc = process.env.NEXT_PUBLIC_RPC_ARBITRUM;
const config = createConfig({
chains: [base, arbitrum, mainnet, sepolia],
transports: {
[base.id]: baseRpc ? http(baseRpc, { batch: true, retryCount: 2, retryDelay: 250 }) : http(undefined, { batch: true, retryCount: 2, retryDelay: 250 }),
[arbitrum.id]: arbitrumRpc ? http(arbitrumRpc, { batch: true, retryCount: 2, retryDelay: 250 }) : http(undefined, { batch: true, retryCount: 2, retryDelay: 250 }),
[mainnet.id]: http(),
[sepolia.id]: http(),
},
ssr: true,
});
const queryClient = new QueryClient();
export function Web3Provider({ children }: PropsWithChildren) {
@@ -44,3 +29,4 @@ export function Web3Provider({ children }: PropsWithChildren) {
</WagmiProvider>
);
}