added network select feature
This commit is contained in:
@@ -36,6 +36,10 @@ const defaultSettings: NotificationSettings = {
|
|||||||
export default function SettingsModal({ open, initial, onClose, onSave }: SettingsModalProps) {
|
export default function SettingsModal({ open, initial, onClose, onSave }: SettingsModalProps) {
|
||||||
const [form, setForm] = useState<NotificationSettings>(initial || defaultSettings);
|
const [form, setForm] = useState<NotificationSettings>(initial || defaultSettings);
|
||||||
const [testStatus, setTestStatus] = useState<string>("");
|
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(() => {
|
useEffect(() => {
|
||||||
if (open) {
|
if (open) {
|
||||||
@@ -45,6 +49,16 @@ export default function SettingsModal({ open, initial, onClose, onSave }: Settin
|
|||||||
if (!merged.ntfyServer) merged.ntfyServer = ENV_NTFY;
|
if (!merged.ntfyServer) merged.ntfyServer = ENV_NTFY;
|
||||||
if (!merged.schedyBaseUrl) merged.schedyBaseUrl = ENV_SCHEDY;
|
if (!merged.schedyBaseUrl) merged.schedyBaseUrl = ENV_SCHEDY;
|
||||||
setForm(merged);
|
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
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [open, initial]);
|
}, [open, initial]);
|
||||||
@@ -284,6 +298,41 @@ export default function SettingsModal({ open, initial, onClose, onSave }: Settin
|
|||||||
</div>
|
</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>
|
||||||
|
|
||||||
<div className="mt-4 flex justify-end gap-2">
|
<div className="mt-4 flex justify-end gap-2">
|
||||||
@@ -307,7 +356,27 @@ export default function SettingsModal({ open, initial, onClose, onSave }: Settin
|
|||||||
<button
|
<button
|
||||||
className="rounded bg-indigo-600 px-3 py-1.5 disabled:opacity-50"
|
className="rounded bg-indigo-600 px-3 py-1.5 disabled:opacity-50"
|
||||||
disabled={saveDisabled}
|
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
|
Save
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -10,16 +10,32 @@ const metadata = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Prefer custom RPCs to avoid public-provider rate limits (429)
|
// Prefer custom RPCs to avoid public-provider rate limits (429)
|
||||||
const baseRpc = process.env.NEXT_PUBLIC_RPC_BASE;
|
// Support runtime overrides via localStorage:
|
||||||
const arbitrumRpc = process.env.NEXT_PUBLIC_RPC_ARBITRUM;
|
// - 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 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({
|
export const config = createConfig({
|
||||||
chains: [base, arbitrum, ...(enableMainnet ? [mainnet] : []), sepolia],
|
chains: [base, arbitrum, ...(enableMainnet ? [mainnet] : []), sepolia],
|
||||||
transports: {
|
transports: {
|
||||||
[base.id]: baseRpc ? http(baseRpc, { batch: true, retryCount: 2, retryDelay: 250 }) : http(undefined, { batch: true, retryCount: 2, retryDelay: 250 }),
|
[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 }),
|
[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(),
|
[sepolia.id]: http(),
|
||||||
},
|
},
|
||||||
ssr: true,
|
ssr: true,
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { WagmiProvider, createConfig, http } from 'wagmi';
|
import { WagmiProvider } from 'wagmi';
|
||||||
import { mainnet, sepolia, base, arbitrum } from 'wagmi/chains';
|
|
||||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||||
import { PropsWithChildren, useEffect, useState } from 'react';
|
import { PropsWithChildren, useEffect, useState } from 'react';
|
||||||
|
import { config } from '../config/web3';
|
||||||
|
|
||||||
const metadata = {
|
const metadata = {
|
||||||
name: 'MortgageFi',
|
name: 'MortgageFi',
|
||||||
@@ -12,21 +12,6 @@ const metadata = {
|
|||||||
icons: ['https://mortgagefi.app/logo.png']
|
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();
|
const queryClient = new QueryClient();
|
||||||
|
|
||||||
export function Web3Provider({ children }: PropsWithChildren) {
|
export function Web3Provider({ children }: PropsWithChildren) {
|
||||||
@@ -44,3 +29,4 @@ export function Web3Provider({ children }: PropsWithChildren) {
|
|||||||
</WagmiProvider>
|
</WagmiProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Submodule submodules/schedy updated: 595a9232cc...4a5a6a5aad
Reference in New Issue
Block a user