diff --git a/src/App.routes.tsx b/src/App.routes.tsx index 7fbefdd28..fd9bff38c 100644 --- a/src/App.routes.tsx +++ b/src/App.routes.tsx @@ -11,6 +11,7 @@ import { InnerTransactionPage } from './features/transactions/pages/inner-transa import { AccountPage, accountPageTitle } from './features/accounts/pages/account-page' import { AssetPage, assetPageTitle } from './features/assets/pages/asset-page' import { ApplicationPage, applicationPageTitle } from './features/applications/pages/application-page' +import { SettingsPage } from './features/settings/pages/settings-page' export const routes = evalTemplates([ { @@ -88,6 +89,10 @@ export const routes = evalTemplates([ template: Urls.AppStudio, element:
App Studio
, }, + { + template: Urls.Settings, + element: , + }, ], }, ]) diff --git a/src/App.tsx b/src/App.tsx index c892af60a..c4c80117c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -4,6 +4,7 @@ import { RouterProvider, createBrowserRouter } from 'react-router-dom' import { ThemeProvider } from './features/theme/context/theme-provider' import { LayoutProvider } from './features/layout/context/layout-provider' import { TooltipProvider } from './features/common/components/tooltip' +import { SettingsProvider } from './features/settings/components/settings-provider' const router = createBrowserRouter(routes) @@ -11,9 +12,11 @@ function App() { return ( - - - + + + + + ) diff --git a/src/assets/icons/cog.svg b/src/assets/icons/cog.svg new file mode 100644 index 000000000..400cb30f2 --- /dev/null +++ b/src/assets/icons/cog.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/features/common/components/icons/cog.tsx b/src/features/common/components/icons/cog.tsx new file mode 100644 index 000000000..75190c5fb --- /dev/null +++ b/src/features/common/components/icons/cog.tsx @@ -0,0 +1,27 @@ +import type { SVGProps } from 'react' +const SvgCog = (props: SVGProps) => ( + + + + + + + + + +) +export default SvgCog diff --git a/src/features/common/data/index.ts b/src/features/common/data/index.ts index 63e102270..ceaa965b5 100644 --- a/src/features/common/data/index.ts +++ b/src/features/common/data/index.ts @@ -1,16 +1,16 @@ import { Config, getAlgoClient, getAlgoIndexerClient } from '@algorandfoundation/algokit-utils' +import { NetworkConfig, localnetConfig } from '../../settings/data/network' export * from './atom-with-debounce' Config.configure({ logger: Config.getLogger(true), }) -export const indexer = getAlgoIndexerClient({ - server: 'https://mainnet-idx.algonode.cloud/', - port: 443, -}) +export let indexer = getAlgoIndexerClient(localnetConfig.indexer) -export const algod = getAlgoClient({ - server: 'https://mainnet-api.algonode.cloud/', - port: 443, -}) +export let algod = getAlgoClient(localnetConfig.algod) + +export const setNetwork = (networkConfig: NetworkConfig) => { + indexer = getAlgoIndexerClient(networkConfig.indexer) + algod = getAlgoClient(networkConfig.algod) +} diff --git a/src/features/layout/components/header.tsx b/src/features/layout/components/header.tsx index 254f79749..e03a3c200 100644 --- a/src/features/layout/components/header.tsx +++ b/src/features/layout/components/header.tsx @@ -1,21 +1,23 @@ import { cn } from '@/features/common/utils' import { ThemeToggle } from '@/features/theme/components/theme-toggle' -import { NetworkSelect } from './network-select' import { ConnectWallet } from './connect-wallet' import { Search } from '@/features/search/components/search' +import { useNetworkConfig } from '@/features/settings/data' type Props = { className?: string } export function Header({ className }: Props) { + const networkConfig = useNetworkConfig() + return (
-
- +
+
diff --git a/src/features/layout/components/left-side-bar-menu.tsx b/src/features/layout/components/left-side-bar-menu.tsx index 384b34ad1..b149a7a37 100644 --- a/src/features/layout/components/left-side-bar-menu.tsx +++ b/src/features/layout/components/left-side-bar-menu.tsx @@ -10,6 +10,7 @@ import SvgChevronLeft from '@/features/common/components/icons/chevron-left' import { useCallback } from 'react' import { useLayout } from '../hooks/use-layout' import SvgChevronRight from '@/features/common/components/icons/chevron-right' +import SvgCog from '@/features/common/components/icons/cog' type Props = { className?: string @@ -20,6 +21,7 @@ export function LeftSideBarMenu({ className }: Props) { { urlTemplate: Urls.Index, icon: , text: 'Home' }, { urlTemplate: Urls.Explore, icon: , text: 'Explore' }, { urlTemplate: Urls.AppStudio, icon: , text: 'App Studio' }, + { urlTemplate: Urls.Settings, icon: , text: 'Settings' }, ] const { isLeftSideBarExpanded, setIsLeftSideBarExpanded } = useLayout() diff --git a/src/features/layout/components/network-select.tsx b/src/features/layout/components/network-select.tsx index 9d29d255f..00c5f1a92 100644 --- a/src/features/layout/components/network-select.tsx +++ b/src/features/layout/components/network-select.tsx @@ -1,21 +1,28 @@ +import { selectedNetworkAtom, networksConfigs } from '@/features/settings/data' import { Label } from '@/features/common/components/label' -import { Select, SelectContent, SelectItem, SelectTrigger } from '@/features/common/components/select' +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/features/common/components/select' import { cn } from '@/features/common/utils' +import { useAtom } from 'jotai' +import { settingsStore } from '@/features/settings/data' export function NetworkSelect() { + const [selectedNetwork, setSelectedNetwork] = useAtom(selectedNetworkAtom, { store: settingsStore }) + return (
- setSelectedNetwork(value)} value={selectedNetwork}> - Network + - Localnet - Testnet - Mainnet + {networksConfigs.map((item) => ( + + {item.name} + + ))}
diff --git a/src/features/settings/components/settings-provider.tsx b/src/features/settings/components/settings-provider.tsx new file mode 100644 index 000000000..a82427c3e --- /dev/null +++ b/src/features/settings/components/settings-provider.tsx @@ -0,0 +1,25 @@ +import { Provider, createStore } from 'jotai' +import { useNetworkConfig } from '../data/network' +import { useEffect } from 'react' +import { setNetwork } from '../../common/data' + +type Props = { + children: React.ReactNode +} + +export let dataStore = createStore() + +export function SettingsProvider({ children }: Props) { + const networkConfig = useNetworkConfig() + + useEffect(() => { + setNetwork(networkConfig) + dataStore = createStore() + }, [networkConfig]) + + return ( + + {children} + + ) +} diff --git a/src/features/settings/components/settings.tsx b/src/features/settings/components/settings.tsx new file mode 100644 index 000000000..0ab5414f2 --- /dev/null +++ b/src/features/settings/components/settings.tsx @@ -0,0 +1,5 @@ +import { NetworkSelect } from '@/features/layout/components/network-select' + +export function Settings() { + return +} diff --git a/src/features/settings/data/index.ts b/src/features/settings/data/index.ts new file mode 100644 index 000000000..623960828 --- /dev/null +++ b/src/features/settings/data/index.ts @@ -0,0 +1,2 @@ +export * from './settings' +export * from './network' diff --git a/src/features/settings/data/network.ts b/src/features/settings/data/network.ts new file mode 100644 index 000000000..b8567c0d1 --- /dev/null +++ b/src/features/settings/data/network.ts @@ -0,0 +1,78 @@ +import { atom, useAtomValue } from 'jotai' +import { atomWithStorage } from 'jotai/utils' +import { settingsStore } from './settings' + +export type NetworkConfig = { + id: string + name: string + indexer: { + server: string + port: number + token?: string + } + algod: { + server: string + port: number + token?: string + } +} + +export const mainnetConfig: NetworkConfig = { + id: 'mainnet', + name: 'MainNet', + indexer: { + server: 'https://mainnet-idx.algonode.cloud/', + port: 443, + }, + algod: { + server: 'https://mainnet-api.algonode.cloud/', + port: 443, + }, +} +const testnetConfig: NetworkConfig = { + id: 'testnet', + name: 'TestNet', + indexer: { + server: 'https://testnet-idx.algonode.cloud/', + port: 443, + }, + algod: { + server: 'https://testnet-api.algonode.cloud/', + port: 443, + }, +} +export const localnetConfig: NetworkConfig = { + id: 'localnet', + name: 'LocalNet', + indexer: { + server: 'http://localhost/', + port: 8980, + token: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + }, + algod: { + server: 'http://localhost/', + port: 4001, + token: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + }, +} + +export const networksConfigs = [mainnetConfig, testnetConfig, localnetConfig] + +export const selectedNetworkAtom = atomWithStorage('network', localnetConfig.id, undefined, { getOnInit: true }) + +const networkConfigAtom = atom((get) => { + const id = get(selectedNetworkAtom) + const config = networksConfigs.find((n) => n.id === id) + + if (!config) { + // eslint-disable-next-line no-console + console.warn(`Unknown network: ${id}, fallback to ${localnetConfig.name}`) + return localnetConfig + } + + return config +}) + +export const useNetworkConfig = () => { + return useAtomValue(networkConfigAtom, { store: settingsStore }) +} diff --git a/src/features/settings/data/settings.ts b/src/features/settings/data/settings.ts new file mode 100644 index 000000000..b4c12b7b2 --- /dev/null +++ b/src/features/settings/data/settings.ts @@ -0,0 +1,3 @@ +import { createStore } from 'jotai' + +export const settingsStore = createStore() diff --git a/src/features/settings/pages/settings-page.tsx b/src/features/settings/pages/settings-page.tsx new file mode 100644 index 000000000..1b85b1a35 --- /dev/null +++ b/src/features/settings/pages/settings-page.tsx @@ -0,0 +1,11 @@ +import { cn } from '@/features/common/utils' +import { Settings } from '../components/settings' + +export function SettingsPage() { + return ( +
+

Settings

+ +
+ ) +} diff --git a/src/routes/urls.ts b/src/routes/urls.ts index 91ca62563..36e181f7b 100644 --- a/src/routes/urls.ts +++ b/src/routes/urls.ts @@ -40,4 +40,5 @@ export const Urls = { }), }), AppStudio: UrlTemplate`/app-studio`, + Settings: UrlTemplate`/settings`, }