Skip to content

Commit 1e9e16c

Browse files
committed
feat(examples): add network config UI to React and Vue examples
Add network configuration forms to React and Vue examples with styling: - Add config form component with server/port/token inputs - Add form styling for light/dark modes - Move network controls to separate component - Update imports and component structure The network configuration UI allows users to view and modify the algod node configuration for each network.
1 parent 1600f4e commit 1e9e16c

File tree

8 files changed

+440
-94
lines changed

8 files changed

+440
-94
lines changed

Diff for: examples/react-ts/src/App.css

+63
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,66 @@
103103
animation: logo-spin infinite 20s linear;
104104
}
105105
}
106+
107+
.config-section {
108+
width: 100%;
109+
max-width: 500px;
110+
margin-top: 1em;
111+
}
112+
113+
.config-form {
114+
display: flex;
115+
flex-direction: column;
116+
gap: 1em;
117+
margin: 1em 0;
118+
padding: 1em;
119+
border: 1px solid rgba(255, 255, 255, 0.1);
120+
border-radius: 4px;
121+
}
122+
123+
.form-group {
124+
display: flex;
125+
flex-direction: column;
126+
gap: 0.5em;
127+
text-align: left;
128+
}
129+
130+
.form-group label {
131+
font-size: 0.9em;
132+
opacity: 0.8;
133+
}
134+
135+
.form-group input {
136+
padding: 0.5em;
137+
border: 1px solid rgba(255, 255, 255, 0.1);
138+
border-radius: 4px;
139+
background: rgba(0, 0, 0, 0.1);
140+
color: inherit;
141+
}
142+
143+
.current-config {
144+
margin-top: 1em;
145+
text-align: left;
146+
}
147+
148+
.current-config h5 {
149+
margin: 0 0 0.5em 0;
150+
font-size: 0.9em;
151+
opacity: 0.8;
152+
}
153+
154+
.current-config pre {
155+
padding: 1em;
156+
background: rgba(0, 0, 0, 0.1);
157+
border-radius: 4px;
158+
font-size: 0.9em;
159+
overflow-x: auto;
160+
}
161+
162+
.error-message {
163+
margin-top: 1em;
164+
padding: 0.5em 1em;
165+
color: #ff4444;
166+
background: rgba(255, 68, 68, 0.1);
167+
border-radius: 4px;
168+
}

Diff for: examples/react-ts/src/App.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { NetworkId, WalletId, WalletManager, WalletProvider } from '@txnlab/use-wallet-react'
22
import { Connect } from './Connect'
3+
import { NetworkControls } from './NetworkControls'
34
import reactLogo from './assets/react.svg'
45
import viteLogo from '/vite.svg'
56
import './App.css'
@@ -45,6 +46,7 @@ function App() {
4546
</a>
4647
</div>
4748
<h1>@txnlab/use-wallet-react</h1>
49+
<NetworkControls />
4850
<Connect />
4951
</WalletProvider>
5052
)

Diff for: examples/react-ts/src/Connect.tsx

+2-32
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import { NetworkId, WalletId, useNetwork, useWallet, type Wallet } from '@txnlab/use-wallet-react'
1+
import { useWallet, WalletId, type Wallet } from '@txnlab/use-wallet-react'
22
import algosdk from 'algosdk'
33
import * as React from 'react'
44

55
export function Connect() {
6-
const { activeAddress, transactionSigner, wallets } = useWallet()
7-
const { algodClient, activeNetwork, setActiveNetwork } = useNetwork()
6+
const { algodClient, activeAddress, transactionSigner, wallets } = useWallet()
87

98
const [isSending, setIsSending] = React.useState(false)
109
const [magicEmail, setMagicEmail] = React.useState('')
@@ -71,35 +70,6 @@ export function Connect() {
7170

7271
return (
7372
<div>
74-
<div className="network-group">
75-
<h4>
76-
Current Network: <span className="active-network">{activeNetwork}</span>
77-
</h4>
78-
<div className="network-buttons">
79-
<button
80-
type="button"
81-
onClick={() => setActiveNetwork(NetworkId.BETANET)}
82-
disabled={activeNetwork === NetworkId.BETANET}
83-
>
84-
Set to Betanet
85-
</button>
86-
<button
87-
type="button"
88-
onClick={() => setActiveNetwork(NetworkId.TESTNET)}
89-
disabled={activeNetwork === NetworkId.TESTNET}
90-
>
91-
Set to Testnet
92-
</button>
93-
<button
94-
type="button"
95-
onClick={() => setActiveNetwork(NetworkId.MAINNET)}
96-
disabled={activeNetwork === NetworkId.MAINNET}
97-
>
98-
Set to Mainnet
99-
</button>
100-
</div>
101-
</div>
102-
10373
{wallets.map((wallet) => (
10474
<div key={wallet.id} className="wallet-group">
10575
<h4>

Diff for: examples/react-ts/src/NetworkControls.tsx

+144
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import { AlgodConfig, NetworkId, useNetwork } from '@txnlab/use-wallet-react'
2+
import * as React from 'react'
3+
4+
export function NetworkControls() {
5+
const {
6+
activeNetwork,
7+
networks,
8+
activeNetworkConfig,
9+
setActiveNetwork,
10+
updateNetworkAlgod,
11+
resetNetworkConfig
12+
} = useNetwork()
13+
14+
const [error, setError] = React.useState<string>('')
15+
const [showConfig, setShowConfig] = React.useState(false)
16+
17+
const [configForm, setConfigForm] = React.useState<Partial<AlgodConfig>>({
18+
baseServer: activeNetworkConfig.algod.baseServer,
19+
port: activeNetworkConfig.algod.port?.toString() || '',
20+
token: activeNetworkConfig.algod.token?.toString() || ''
21+
})
22+
23+
React.useEffect(() => {
24+
setConfigForm({
25+
baseServer: activeNetworkConfig.algod.baseServer,
26+
port: activeNetworkConfig.algod.port?.toString() || '',
27+
token: activeNetworkConfig.algod.token?.toString() || ''
28+
})
29+
}, [activeNetworkConfig])
30+
31+
const handleNetworkSwitch = async (networkId: NetworkId) => {
32+
try {
33+
setError('')
34+
await setActiveNetwork(networkId)
35+
} catch (error) {
36+
setError(error instanceof Error ? error.message : 'Failed to switch networks')
37+
}
38+
}
39+
40+
const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
41+
const { name, value } = event.target
42+
setConfigForm((prev) => ({ ...prev, [name]: value }))
43+
}
44+
45+
const handleConfigSubmit = async (event: React.FormEvent) => {
46+
event.preventDefault()
47+
try {
48+
setError('')
49+
updateNetworkAlgod(activeNetwork, {
50+
baseServer: configForm.baseServer,
51+
port: configForm.port || undefined,
52+
token: configForm.token
53+
})
54+
} catch (error) {
55+
setError(error instanceof Error ? error.message : 'Failed to update node configuration')
56+
}
57+
}
58+
59+
const handleResetConfig = () => {
60+
try {
61+
setError('')
62+
resetNetworkConfig(activeNetwork)
63+
} catch (error) {
64+
setError(error instanceof Error ? error.message : 'Failed to reset node configuration')
65+
}
66+
}
67+
68+
return (
69+
<div className="network-group">
70+
<h4>Network Controls</h4>
71+
<div className="active-network">Active: {activeNetwork}</div>
72+
73+
<div className="network-buttons">
74+
{Object.keys(networks).map((networkId) => (
75+
<button
76+
key={networkId}
77+
onClick={() => handleNetworkSwitch(networkId as NetworkId)}
78+
disabled={networkId === activeNetwork}
79+
>
80+
Switch to {networkId}
81+
</button>
82+
))}
83+
</div>
84+
85+
<div className="config-section">
86+
<button onClick={() => setShowConfig(!showConfig)}>
87+
{showConfig ? 'Hide' : 'Show'} Network Config
88+
</button>
89+
90+
{showConfig && (
91+
<form onSubmit={handleConfigSubmit} className="config-form">
92+
<div className="form-group">
93+
<label htmlFor="baseServer">Base Server:</label>
94+
<input
95+
type="text"
96+
id="baseServer"
97+
name="baseServer"
98+
value={configForm.baseServer}
99+
onChange={handleInputChange}
100+
placeholder="https://mainnet-api.4160.nodely.dev"
101+
/>
102+
</div>
103+
104+
<div className="form-group">
105+
<label htmlFor="port">Port:</label>
106+
<input
107+
type="text"
108+
id="port"
109+
name="port"
110+
value={configForm.port}
111+
onChange={handleInputChange}
112+
placeholder="443"
113+
/>
114+
</div>
115+
116+
<div className="form-group">
117+
<label htmlFor="token">Token:</label>
118+
<input
119+
type="text"
120+
id="token"
121+
name="token"
122+
value={configForm.token?.toString() || ''}
123+
onChange={handleInputChange}
124+
placeholder="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
125+
/>
126+
</div>
127+
128+
<button type="submit">Update Configuration</button>
129+
<button type="button" onClick={handleResetConfig}>
130+
Reset Configuration
131+
</button>
132+
</form>
133+
)}
134+
135+
<div className="current-config">
136+
<h5>Current Algod Configuration:</h5>
137+
<pre>{JSON.stringify(activeNetworkConfig.algod, null, 2)}</pre>
138+
</div>
139+
</div>
140+
141+
{error && <div className="error-message">{error}</div>}
142+
</div>
143+
)
144+
}

Diff for: examples/vue-ts/src/App.vue

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script setup lang="ts">
22
import Connect from './components/Connect.vue'
3+
import NetworkControls from './components/NetworkControls.vue'
34
</script>
45

56
<template>
@@ -12,6 +13,7 @@ import Connect from './components/Connect.vue'
1213
</a>
1314
</div>
1415
<h1>@txnlab/use-wallet-vue</h1>
16+
<NetworkControls />
1517
<Connect />
1618
</template>
1719

@@ -29,3 +31,4 @@ import Connect from './components/Connect.vue'
2931
filter: drop-shadow(0 0 2em #42b883aa);
3032
}
3133
</style>
34+

Diff for: examples/vue-ts/src/components/Connect.vue

+3-62
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
<script setup lang="ts">
2-
import { NetworkId, WalletId, useNetwork, useWallet, type Wallet } from '@txnlab/use-wallet-vue'
2+
import { WalletId, useWallet, type Wallet } from '@txnlab/use-wallet-vue'
33
import algosdk from 'algosdk'
44
import { ref } from 'vue'
55
6-
const { transactionSigner, wallets } = useWallet()
7-
const { algodClient, activeNetwork, setActiveNetwork } = useNetwork()
6+
const { algodClient, transactionSigner, wallets } = useWallet()
87
98
const isSending = ref(false)
109
const magicEmail = ref('')
@@ -65,35 +64,6 @@ const sendTransaction = async (wallet: Wallet) => {
6564

6665
<template>
6766
<div>
68-
<div className="network-group">
69-
<h4>
70-
Current Network: <span className="active-network">{{ activeNetwork }}</span>
71-
</h4>
72-
<div className="network-buttons">
73-
<button
74-
type="button"
75-
@click="() => setActiveNetwork(NetworkId.BETANET)"
76-
:disabled="activeNetwork === NetworkId.BETANET"
77-
>
78-
Set to Betanet
79-
</button>
80-
<button
81-
type="button"
82-
@click="() => setActiveNetwork(NetworkId.TESTNET)"
83-
:disabled="activeNetwork === NetworkId.TESTNET"
84-
>
85-
Set to Testnet
86-
</button>
87-
<button
88-
type="button"
89-
@click="() => setActiveNetwork(NetworkId.MAINNET)"
90-
:disabled="activeNetwork === NetworkId.MAINNET"
91-
>
92-
Set to Mainnet
93-
</button>
94-
</div>
95-
</div>
96-
9767
<div v-for="wallet in wallets" :key="wallet.id" class="wallet-group">
9868
<h4>{{ wallet.metadata.name }} <span v-if="wallet.isActive">[active]</span></h4>
9969
<div class="wallet-buttons">
@@ -143,36 +113,6 @@ const sendTransaction = async (wallet: Wallet) => {
143113
</template>
144114

145115
<style scoped>
146-
.network-group {
147-
display: flex;
148-
flex-direction: column;
149-
align-items: center;
150-
gap: 1em;
151-
margin: 2em;
152-
padding: 2em;
153-
background-color: light-dark(rgba(0, 0, 0, 0.025), rgba(255, 255, 255, 0.025));
154-
border-color: light-dark(rgba(0, 0, 0, 0.1), rgba(255, 255, 255, 0.1));
155-
border-style: solid;
156-
border-width: 1px;
157-
border-radius: 8px;
158-
}
159-
160-
.network-group h4 {
161-
margin: 0;
162-
}
163-
164-
.network-group .active-network {
165-
text-transform: capitalize;
166-
}
167-
168-
.network-buttons {
169-
display: flex;
170-
align-items: center;
171-
justify-content: center;
172-
flex-wrap: wrap;
173-
gap: 0.5em;
174-
}
175-
176116
.wallet-group {
177117
display: flex;
178118
flex-direction: column;
@@ -220,3 +160,4 @@ const sendTransaction = async (wallet: Wallet) => {
220160
}
221161
}
222162
</style>
163+

0 commit comments

Comments
 (0)