Skip to content

Commit 6c6a2cd

Browse files
author
Harshdev098
committed
Merge dev into main
2 parents 7b094fb + a2f023c commit 6c6a2cd

37 files changed

Lines changed: 4284 additions & 1397 deletions

package-lock.json

Lines changed: 1198 additions & 39 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/App.css

Lines changed: 1401 additions & 354 deletions
Large diffs are not rendered by default.

src/Components/AddFederation.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import Alerts from './Alerts'
99
import { JoinFederation as JoinFederationService } from '../services/FederationService'
1010
import QrScanner from 'qr-scanner'
1111
import NProgress from 'nprogress'
12+
import logger from '../utils/logger'
1213

1314

1415
export default function AddFederation({ setJoinForm }: { setJoinForm: React.Dispatch<React.SetStateAction<boolean>> }) {
@@ -29,7 +30,7 @@ export default function AddFederation({ setJoinForm }: { setJoinForm: React.Disp
2930
const code = inviteCode.current?.value?.trim() || qrData
3031
if (!code) return; // invitecode should not be empty
3132
if (wallet?.isOpen()) {
32-
console.log("wallet is open")
33+
logger.log("wallet is open")
3334
// let result = await wallet.federation.getFederationId();
3435
// localStorage.setItem('activeFederation', result)
3536
// dispatch(setFederationId(result))
@@ -67,7 +68,7 @@ export default function AddFederation({ setJoinForm }: { setJoinForm: React.Disp
6768
videoRef.current,
6869
async (result) => {
6970
if (result?.data) {
70-
console.log("the result from qr is ", result.data)
71+
logger.log("the result from qr is ", result.data)
7172
await handleJoinFederation({ preventDefault: () => { } } as React.FormEvent, result.data)
7273
scannerRef.current?.destroy()
7374
scannerRef.current = null;
@@ -76,16 +77,16 @@ export default function AddFederation({ setJoinForm }: { setJoinForm: React.Disp
7677
{ returnDetailedScanResult: true }
7778
)
7879
scannerRef.current.start().then(() => {
79-
console.log("Camera started successfully");
80+
logger.log("Camera started successfully");
8081
}).catch((err) => {
81-
console.error("Camera access denied:", err);
82+
logger.log("Camera access denied:", err);
8283
dispatch(setError('Camera access denied!'))
8384
setTimeout(() => {
8485
dispatch(setError(''))
8586
}, 2000);
8687
});
8788
} catch (err) {
88-
console.log("an error occured while scanning")
89+
logger.log("an error occured while scanning")
8990
dispatch(setError("Error occured while scanning"))
9091
setTimeout(() => {
9192
dispatch(setError(''))

src/Components/Balance.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,7 @@ export default function Balance() {
3131
if (value === undefined) {
3232
throw new Error("Failed to fetch balance")
3333
} else {
34-
console.log("fetched value is ",value,currency)
3534
const convertedAmount=await convertFromMsat(value,currency)
36-
console.log("converted value is ",convertedAmount)
3735
dispatch(setBalance(convertedAmount))
3836
}
3937
} catch (err) {

src/Components/BasicSettings.tsx

Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
import { useState, useContext } from "react";
2+
import { useDispatch, useSelector } from 'react-redux'
3+
import type { RootState } from '../redux/store'
4+
import { setMode } from '../redux/slices/Mode';
5+
import logger from "../utils/logger";
6+
import WalletContext from "../context/wallet";
7+
import { setCurrency } from '../redux/slices/Balance';
8+
import { useNavigate } from "react-router";
9+
import LoadingContext from '../context/loader';
10+
import NProgress from 'nprogress';
11+
// import { DownloadTransactionsCSV } from "../services/DownloadQR";
12+
import Alerts from "./Alerts";
13+
14+
15+
export default function BasicSettings() {
16+
const dispatch = useDispatch()
17+
const { metaData } = useSelector((state: RootState) => state.federationdetails)
18+
const [enabledLocation, setEnabledLocation] = useState(localStorage.getItem('locationAccess') === 'true' ? true : false)
19+
const { mode } = useSelector((state: RootState) => state.Mode)
20+
const { wallet, isDebug, toggleDebug } = useContext(WalletContext)
21+
const { currency } = useSelector((state: RootState) => state.balance)
22+
const { federationId } = useSelector((state: RootState) => state.activeFederation)
23+
const { setLoading } = useContext(LoadingContext);
24+
const [error, setError] = useState('')
25+
const navigate = useNavigate()
26+
27+
28+
const handleCurrencyChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
29+
const selectedCurrency = e.target.value;
30+
dispatch(setCurrency(selectedCurrency));
31+
localStorage.setItem('walletCurrency', selectedCurrency)
32+
};
33+
34+
const handleToggleLocation = (e: React.ChangeEvent<HTMLInputElement>) => {
35+
const newValue = e.target.checked;
36+
if (enabledLocation === true && newValue === false) {
37+
if (confirm("all the geoLocation data will be removed from your storage")) {
38+
localStorage.setItem('locationAccess', newValue.toString());
39+
localStorage.removeItem('paymentLocations')
40+
setEnabledLocation(newValue);
41+
}
42+
} else {
43+
setEnabledLocation(newValue);
44+
localStorage.setItem('locationAccess', newValue.toString());
45+
}
46+
}
47+
48+
const toggleMode = (e: React.ChangeEvent<HTMLInputElement>) => {
49+
const newValue = e.target.checked
50+
dispatch(setMode(newValue))
51+
localStorage.setItem('appMode', JSON.stringify(newValue))
52+
logger.log("mode toggled")
53+
}
54+
55+
const handleLeaveFederations = async () => {
56+
try {
57+
NProgress.start()
58+
setLoading(true)
59+
await wallet.cleanup();
60+
logger.log('wallet cleanup called')
61+
await wallet.waitForOpen().catch(() => {
62+
logger.log('Wallet is closed');
63+
});
64+
indexedDB.deleteDatabase(`${localStorage.getItem('walletName')}`);
65+
localStorage.removeItem('walletName')
66+
localStorage.removeItem('activeFederation')
67+
localStorage.removeItem('WalletNostrKeys')
68+
localStorage.removeItem('ClientRelayKeys')
69+
localStorage.removeItem('nwcRelays')
70+
localStorage.removeItem('nwcEnabled')
71+
if (!wallet.isOpen()) {
72+
logger.log('wallet open ', wallet.isOpen())
73+
navigate('/')
74+
window.location.reload()
75+
}
76+
} catch (err) {
77+
logger.log("an error occured")
78+
setError(err instanceof Error ? err.message : String(err))
79+
setTimeout(() => {
80+
setError('')
81+
}, 3000);
82+
} finally {
83+
NProgress.done()
84+
setLoading(false)
85+
}
86+
}
87+
88+
const handleDownloadTransactions = async () => {
89+
// try {
90+
// NProgress.start()
91+
// setLoading(true)
92+
// const transactions = await wallet.federation.listTransactions()
93+
// if (transactions.length === 0) throw new Error("0 Transactions found")
94+
// DownloadTransactionsCSV(transactions)
95+
// } catch (err) {
96+
// logger.log('an error occured')
97+
// setError(err instanceof Error ? err.message : String(err))
98+
// setTimeout(() => {
99+
// setError('')
100+
// }, 3000);
101+
// } finally {
102+
// NProgress.done()
103+
// setLoading(false)
104+
// }
105+
}
106+
107+
return (
108+
<>
109+
{error && <Alerts Error={error} Result='' />}
110+
111+
<div className="settings-container">
112+
{/* Federation Information Section */}
113+
{(metaData?.federation_expiry_timestamp || metaData?.pinned_message || metaData?.welcome_message) && (
114+
<div className="settings-section">
115+
<h2 className="section-title">Federation Information</h2>
116+
<div className="info-cards">
117+
{metaData?.federation_expiry_timestamp && (
118+
<div className="info-card">
119+
<div className="info-header">
120+
<h3>Federation Expiry</h3>
121+
</div>
122+
<div className="info-content">
123+
<p>{metaData.federation_expiry_timestamp}</p>
124+
</div>
125+
</div>
126+
)}
127+
128+
{metaData?.pinned_message && (
129+
<div className="info-card">
130+
<div className="info-header">
131+
<h3>Pinned Message</h3>
132+
</div>
133+
<div className="info-content">
134+
<p>{metaData.pinned_message}</p>
135+
</div>
136+
</div>
137+
)}
138+
139+
{metaData?.welcome_message && (
140+
<div className="info-card">
141+
<div className="info-header">
142+
<h3>Welcome Message</h3>
143+
</div>
144+
<div className="info-content">
145+
<p>{metaData.welcome_message}</p>
146+
</div>
147+
</div>
148+
)}
149+
</div>
150+
</div>
151+
)}
152+
153+
{/* Preferences Section */}
154+
<div className="settings-section">
155+
<h2 className="section-title">Preferences</h2>
156+
<div className="settings-grid">
157+
<div className="setting-item">
158+
<div className="setting-info">
159+
<h3>Geolocation</h3>
160+
<p>Fedimint will not track users data. Location will be saved locally.</p>
161+
</div>
162+
<div className="setting-control">
163+
<label className="toggle-switch">
164+
<input
165+
type="checkbox"
166+
checked={enabledLocation}
167+
onChange={handleToggleLocation}
168+
/>
169+
<span className="toggle-slider"></span>
170+
</label>
171+
</div>
172+
</div>
173+
174+
<div className="setting-item">
175+
<div className="setting-info">
176+
<h3>Theme</h3>
177+
<p>Enable {mode === true ? 'Dark' : 'Light'} mode</p>
178+
</div>
179+
<div className="setting-control">
180+
<label className="toggle-switch">
181+
<input
182+
type="checkbox"
183+
checked={mode}
184+
onChange={toggleMode}
185+
/>
186+
<span className="toggle-slider"></span>
187+
</label>
188+
</div>
189+
</div>
190+
191+
<div className="setting-item">
192+
<div className="setting-info">
193+
<h3>Developer Mode</h3>
194+
<p>{isDebug === true ? 'Disable' : 'Enable'} Developer mode</p>
195+
</div>
196+
<div className="setting-control">
197+
<label className="toggle-switch">
198+
<input
199+
type="checkbox"
200+
checked={isDebug}
201+
onChange={toggleDebug}
202+
/>
203+
<span className="toggle-slider"></span>
204+
</label>
205+
</div>
206+
</div>
207+
</div>
208+
</div>
209+
210+
{/* Configuration Section */}
211+
<div className="settings-section">
212+
<h2 className="section-title">Configuration</h2>
213+
<div className="config-grid">
214+
<div className="config-item">
215+
<label className="config-label">Display Currency</label>
216+
<select className="config-select" value={currency} onChange={handleCurrencyChange}>
217+
<option value={'msat'}>msat</option>
218+
<option value={'sat'}>sat</option>
219+
<option value={'usd'}>USD</option>
220+
<option value={'euro'}>EURO</option>
221+
</select>
222+
</div>
223+
224+
<div className="config-item">
225+
<label className="config-label">Export Transactions</label>
226+
<button className="export-btn" onClick={handleDownloadTransactions}>
227+
<i className="fa-solid fa-download"></i>
228+
Export
229+
</button>
230+
</div>
231+
</div>
232+
</div>
233+
234+
{/* Federations Section */}
235+
<div className="settings-section">
236+
<h2 className="section-title">Federations</h2>
237+
<div className="federation-container">
238+
{metaData && (
239+
<div className="federation-card">
240+
<div className="federation-info">
241+
<h3>{metaData.federation_name}</h3>
242+
<span className="federation-status">Active</span>
243+
</div>
244+
<div className="federation-actions">
245+
<a href={`/fedimint-web-wallet/federation/${federationId || localStorage.getItem('activeFederation')}`} className="action-btn view-btn">
246+
{/* <i className="fa-solid fa-arrow-up-right-from-square"></i> */}
247+
View
248+
</a>
249+
<button className="action-btn leave-btn" onClick={handleLeaveFederations} title="Leave Federation">
250+
{/* <i className="fa-solid fa-arrow-right-from-bracket"></i> */}
251+
Leave
252+
</button>
253+
</div>
254+
</div>
255+
)}
256+
</div>
257+
</div>
258+
</div>
259+
</>
260+
)
261+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import React, { useContext, useEffect, useState } from 'react'
2+
import NostrContext from '../context/nostr';
3+
import logger from '../utils/logger';
4+
import loader from '../assets/loader.webp'
5+
6+
interface DiscoverFederationProps {
7+
setShowFederation: React.Dispatch<React.SetStateAction<boolean>>;
8+
setInviteCode: React.Dispatch<React.SetStateAction<string>>;
9+
joinFederation: (code: string) => Promise<void>
10+
showFederations: React.SetStateAction<boolean>
11+
}
12+
13+
export default function DiscoverFederation({ setShowFederation, showFederations, joinFederation }: DiscoverFederationProps) {
14+
const { DiscoverFederation, discoveredFederations } = useContext(NostrContext)
15+
const [isLoading, setIsLoading] = useState<boolean>(true)
16+
17+
useEffect(() => {
18+
if (showFederations === true) {
19+
logger.log('calling discover federation function')
20+
DiscoverFederation()
21+
setTimeout(() => {
22+
setIsLoading(false)
23+
}, 30000);
24+
}
25+
}, [showFederations])
26+
27+
return (
28+
<div className='federation-discovery'>
29+
<div className='previewData'>
30+
<div className='previewCard'>
31+
<button className='closeButton' onClick={() => setShowFederation(false)}>
32+
<i className="fa-solid fa-xmark"></i>
33+
</button>
34+
<h3>Recommended Federations</h3>
35+
<ul>
36+
{discoveredFederations.map((fed) => (
37+
<li key={fed.inviteCode} onClick={() => joinFederation(fed.inviteCode)}>
38+
<img src={fed.iconUrl} alt={`${fed.federationName} icon`} />
39+
<div className="fed-info">
40+
<h4>{fed.federationName}</h4>
41+
<p>{fed.federationId}</p>
42+
</div>
43+
<div className="arrow-icon">
44+
<i className="fa-solid fa-arrow-right"></i>
45+
</div>
46+
</li>
47+
))}
48+
</ul>
49+
{isLoading && <div style={{ textAlign: 'center', margin: '10px' }}>
50+
<img src={loader} alt="loader" width={'20%'} />
51+
</div>}
52+
</div>
53+
</div>
54+
</div>
55+
)
56+
}

0 commit comments

Comments
 (0)